diff --git a/LICENSE b/LICENSE
index 78f5dc8..e62afe4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020 EWT Project
+Copyright (c) 1998-2020 Declan Traill
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/ReadMe.txt b/ReadMe.txt
new file mode 100644
index 0000000..6d79607
--- /dev/null
+++ b/ReadMe.txt
@@ -0,0 +1,8 @@
+
+This Project was developed in the Delphi RAD Studio:
+Delphi 10.3 Community Edition Version 26.0.36039.7899
+
+It is a non-commercial project written to model Quantum particles: electrons and positrons.
+
+The code is Copyright 1998-2020 by Declan Traill, but may be used by others (and modified
+by them to suit their own needs) so long as the copyright notice and attribution of the code is not removed.
\ No newline at end of file
diff --git a/VectPotential.cfg b/VectPotential.cfg
new file mode 100644
index 0000000..ea5c936
--- /dev/null
+++ b/VectPotential.cfg
@@ -0,0 +1,37 @@
+-$A8
+-$B-
+-$C+
+-$D+
+-$E-
+-$F-
+-$G+
+-$H+
+-$I+
+-$J+
+-$K-
+-$L+
+-$M-
+-$N+
+-$O+
+-$P+
+-$Q+
+-$R+
+-$S-
+-$T-
+-$U-
+-$V+
+-$W-
+-$X+
+-$YD
+-$Z1
+-cg
+-AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+-H+
+-W+
+-M
+-$M16384,16777216
+-K$00400000
+-E"C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential"
+-N"C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential"
+-LE"C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential"
+-LN"C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential"
diff --git a/VectPotential.dof b/VectPotential.dof
new file mode 100644
index 0000000..984efc4
--- /dev/null
+++ b/VectPotential.dof
@@ -0,0 +1,136 @@
+[FileVersion]
+Version=7.0
+[Compiler]
+A=8
+B=0
+C=1
+D=1
+E=0
+F=0
+G=1
+H=1
+I=1
+J=1
+K=0
+L=1
+M=0
+N=1
+O=1
+P=1
+Q=1
+R=1
+S=0
+T=0
+U=0
+V=1
+W=0
+X=1
+Y=1
+Z=1
+ShowHints=1
+ShowWarnings=1
+UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;
+NamespacePrefix=
+SymbolDeprecated=1
+SymbolLibrary=1
+SymbolPlatform=1
+UnitLibrary=1
+UnitPlatform=1
+UnitDeprecated=1
+HResultCompat=1
+HidingMember=1
+HiddenVirtual=1
+Garbage=1
+BoundsError=1
+ZeroNilCompat=1
+StringConstTruncated=1
+ForLoopVarVarPar=1
+TypedConstVarPar=1
+AsgToTypedConst=1
+CaseLabelRange=1
+ForVariable=1
+ConstructingAbstract=1
+ComparisonFalse=1
+ComparisonTrue=1
+ComparingSignedUnsigned=1
+CombiningSignedUnsigned=1
+UnsupportedConstruct=1
+FileOpen=1
+FileOpenUnitSrc=1
+BadGlobalSymbol=1
+DuplicateConstructorDestructor=1
+InvalidDirective=1
+PackageNoLink=1
+PackageThreadVar=1
+ImplicitImport=1
+HPPEMITIgnored=1
+NoRetVal=1
+UseBeforeDef=1
+ForLoopVarUndef=1
+UnitNameMismatch=1
+NoCFGFileFound=1
+MessageDirective=1
+ImplicitVariants=1
+UnicodeToLocale=1
+LocaleToUnicode=1
+ImagebaseMultiple=1
+SuspiciousTypecast=1
+PrivatePropAccessor=1
+UnsafeType=1
+UnsafeCode=1
+UnsafeCast=1
+[Linker]
+MapFile=0
+OutputObjs=0
+ConsoleApp=1
+DebugInfo=0
+RemoteSymbols=0
+MinStackSize=16384
+MaxStackSize=16777216
+ImageBase=4194304
+ExeDescription=VectPotential.exe
+[Directories]
+OutputDir=C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential
+UnitOutputDir=C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential
+PackageDLLOutputDir=C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential
+PackageDCPOutputDir=C:\Users\TOSHIBA\Documents\Physics\Projects\VectPotential
+SearchPath=
+Packages=VCL40;VCLX40;VCLDB40;VCLDBX40;VCLSMP40;QRPT40;TEEUI40;TEEDB40;TEE40;ibevnt40;nmfast40;MS_Direct_Anim
+Conditionals=
+DebugSourceDirs=
+UsePackages=0
+[Parameters]
+RunParams=
+HostApplication=
+Launcher=
+UseLauncher=0
+DebugCWD=
+[Language]
+ActiveLang=
+ProjectLang=
+RootDir=
+[Version Info]
+IncludeVerInfo=0
+AutoIncBuild=0
+MajorVer=1
+MinorVer=0
+Release=0
+Build=0
+Debug=0
+PreRelease=0
+Special=0
+Private=0
+DLL=0
+Locale=3081
+CodePage=1252
+[Version Info Keys]
+CompanyName=
+FileDescription=
+FileVersion=1.0.0.0
+InternalName=
+LegalCopyright=
+LegalTrademarks=
+OriginalFilename=
+ProductName=
+ProductVersion=1.0.0.0
+Comments=
diff --git a/VectPotential.dpr b/VectPotential.dpr
new file mode 100644
index 0000000..94e7001
--- /dev/null
+++ b/VectPotential.dpr
@@ -0,0 +1,23 @@
+program VectPotential;
+
+uses
+ Forms,
+ VectorPotential in 'VectorPotential.pas' {Form1};
+
+// Set IMAGE_FILE_LARGE_ADDRESS_AWARE $0020 (up to 4Gb, rather than 2Gb, on a 64 bit PC)
+// And IMAGE_FILE_NET_RUN_FROM_SWAP $0800
+// And IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP $0400
+// And IMAGE_FILE_RELOCS_STRIPPED $0001
+{$SetPEFlags $0C21}
+
+{$E .exe}
+
+{$R *.RES}
+
+begin
+ Application.Initialize;
+ Application.MainFormOnTaskbar := True;
+ Application.Title := 'VectorPotential';
+ Application.CreateForm(TForm1, Form1);
+ Application.Run;
+end.
diff --git a/VectPotential.dproj b/VectPotential.dproj
new file mode 100644
index 0000000..c446097
--- /dev/null
+++ b/VectPotential.dproj
@@ -0,0 +1,139 @@
+
+
+ {E18C5945-35AB-4027-A61C-B88AB7BCE161}
+ VectPotential.dpr
+ Debug
+ DCC32
+ 18.8
+ VCL
+ True
+ Win32
+ 1
+ Application
+
+
+ true
+
+
+ true
+ Base
+ true
+
+
+ true
+ Base
+ true
+
+
+ 00400000
+ VectPotential.exe
+ VCL40;VCLX40;VCLDB40;VCLDBX40;VCLSMP40;QRPT40;TEEUI40;TEEDB40;TEE40;ibevnt40;nmfast40;MS_Direct_Anim;$(DCC_UsePackage)
+ true
+ true
+ true
+ VectPotential.exe
+ x86
+ true
+ false
+ false
+ true
+ false
+ false
+ 16777216
+ true
+ 1
+ true
+ VectPotential
+ Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;$(DCC_Namespace)
+ 3081
+ CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=
+
+
+ ..\..\..\..\Administrator\Documents\Physics\VectPotential_Electron_WaveFunction_Solved_RELEASE 2\VectPotential.exe
+ C:\Users\Administrator\Documents\Physics\VectPotential_Electron_WaveFunction_Solved_RELEASE 2
+ C:\Users\Administrator\Documents\Physics\VectPotential_Electron_WaveFunction_Solved_RELEASE 2
+ C:\Users\Administrator\Documents\Physics\VectPotential_Electron_WaveFunction_Solved_RELEASE 2
+ C:\Users\Administrator\Documents\Physics\VectPotential_Electron_WaveFunction_Solved_RELEASE 2
+ false
+ RELEASE;$(DCC_Define)
+ 0
+ 0
+
+
+ DEBUG;$(DCC_Define)
+
+
+
+ MainSource
+
+
+
+
+
+ Base
+
+
+ Cfg_2
+ Base
+
+
+ Cfg_1
+ Base
+
+
+
+
+ Delphi.Personality.12
+ VCLApplication
+
+
+
+ VectPotential.dpr
+
+
+ False
+ True
+ False
+ C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2
+ C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2
+
+
+ True
+ False
+ 1
+ 0
+ 0
+ 0
+ False
+ False
+ False
+ False
+ False
+ 3081
+ 1252
+
+
+
+
+ 1.0.0.0
+
+
+
+
+
+ 1.0.0.0
+
+
+
+ Microsoft Office 2000 Sample Automation Server Wrapper Components
+ Microsoft Office XP Sample Automation Server Wrapper Components
+
+
+
+ True
+ False
+
+
+ 12
+
+
diff --git a/VectPotential.dproj.local b/VectPotential.dproj.local
new file mode 100644
index 0000000..3985aef
--- /dev/null
+++ b/VectPotential.dproj.local
@@ -0,0 +1,14 @@
+
+
+
+ 2018/06/15 19:00:18.980.dproj,C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2\VectPotential.dproj=J:\Maple_Corrected\VectPotential.dproj
+ 2018/06/15 19:01:01.060.pas,C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2\VectorPotential.pas=J:\Maple_Corrected\VectorPotential.pas
+ 2018/06/15 19:01:01.060.dfm,C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2\VectorPotential.dfm=J:\Maple_Corrected\VectorPotential.dfm
+ 2018/06/15 19:02:31.310.dproj,J:\Maple_Corrected\VectPotential.dproj=C:\Users\Administrator\Documents\Physics\VectPotential_Solved_RELEASE_2\VectPotential.dproj
+
+
+
+
+
+ Debug
+
diff --git a/VectPotential.dsk b/VectPotential.dsk
new file mode 100644
index 0000000..bc24793
--- /dev/null
+++ b/VectPotential.dsk
@@ -0,0 +1,131 @@
+[Main Window]
+Create=1
+Visible=1
+State=0
+Left=10
+Top=3
+Width=1108
+Height=105
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=1100
+ClientHeight=78
+
+[PropertyInspector]
+Create=1
+Visible=1
+State=0
+Left=6
+Top=114
+Width=190
+Height=716
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=180
+ClientHeight=690
+TBDockHeight=671
+LRDockWidth=193
+Dockable=0
+SplitPos=88
+
+[Closed Files]
+File_0=SourceModule,'E:\Program Files\Borland\Delphi4\Projects\ElecMagnet_3D_Test.dfm',0,1,1,1,1,0,0
+File_1=SourceModule,'E:\Program Files\Borland\Delphi4\Projects\3D-Elec&Mag\ElecMagnet_3D.pas',0,1,897,1,899,0,1
+File_2=SourceModule,'E:\Program Files\Borland\Delphi4\Projects\3D-Elec&Mag\ElecMagnet_3D.dfm',0,1,1,1,1,0,0
+File_3=SourceModule,'E:\Program Files\Borland\Delphi4\Imports\DirectAnimation_TLB.pas',0,1,9,53,27,0,0
+File_4=SourceModule,'E:\Program Files\Borland\Delphi4\Projects\TestApp\Unit1.pas',0,1,99,1,101,0,1
+
+[Modules]
+Module0=C:\Program Files\Borland\Delphi4\Projects\VectPotential\VectorPotential.pas
+Count=1
+EditWindowCount=1
+
+[C:\Program Files\Borland\Delphi4\Projects\VectPotential\VectorPotential.pas]
+ModuleType=SourceModule
+FormState=1
+FormOnTop=0
+
+[C:\Program Files\Borland\Delphi4\Bin\ProjectGroup1.bpg]
+FormState=0
+FormOnTop=0
+
+[C:\Program Files\Borland\Delphi4\Projects\VectPotential\VectPotential.dpr]
+FormState=0
+FormOnTop=0
+
+[EditWindow0]
+CodeExplorer=CodeExplorer@EditWindow0
+MessageView=MessageView@EditWindow0
+Create=1
+Visible=1
+State=0
+Left=48
+Top=116
+Width=936
+Height=542
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=928
+ClientHeight=515
+LeftPanelSize=261
+LeftPanelClients=CodeExplorer@EditWindow0
+LeftPanelData=000004000000000000000000000000000000000000000000000100000000000000000C000000436F64654578706C6F726572FFFFFFFF
+RightPanelSize=0
+BottomPanelSize=0
+BottomPanelClients=MessageView@EditWindow0
+BottomPanelData=00000400010000000B0000004D657373616765566965770000000000000000000000000000000000FFFFFFFF
+ViewCount=1
+CurrentView=0
+View0=0
+
+[CodeExplorer@EditWindow0]
+Create=1
+Visible=1
+State=0
+Left=0
+Top=11
+Width=261
+Height=486
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=261
+ClientHeight=486
+TBDockHeight=305
+LRDockWidth=261
+Dockable=1
+
+[MessageView@EditWindow0]
+Create=1
+Visible=0
+State=0
+Left=-23
+Top=-545
+Width=443
+Height=52
+MaxLeft=-1
+MaxTop=-1
+ClientWidth=443
+ClientHeight=52
+TBDockHeight=52
+LRDockWidth=443
+Dockable=1
+
+[View0]
+Module=C:\Program Files\Borland\Delphi4\Projects\VectPotential\VectorPotential.pas
+CursorX=14
+CursorY=2710
+TopLine=2687
+LeftCol=1
+
+[DockHosts]
+DockHostCount=0
+
+[Watches]
+Count=0
+
+[Breakpoints]
+Count=0
+
+[AddressBreakpoints]
+Count=0
+
diff --git a/VectPotential.exe b/VectPotential.exe
new file mode 100644
index 0000000..710e4b0
Binary files /dev/null and b/VectPotential.exe differ
diff --git a/VectPotential.identcache b/VectPotential.identcache
new file mode 100644
index 0000000..aa08298
Binary files /dev/null and b/VectPotential.identcache differ
diff --git a/VectPotential.res b/VectPotential.res
new file mode 100644
index 0000000..ce704b8
Binary files /dev/null and b/VectPotential.res differ
diff --git a/VectPotential.txt.dproj.local b/VectPotential.txt.dproj.local
new file mode 100644
index 0000000..d576f03
--- /dev/null
+++ b/VectPotential.txt.dproj.local
@@ -0,0 +1,2 @@
+
+
diff --git a/VectPotential.txt.identcache b/VectPotential.txt.identcache
new file mode 100644
index 0000000..be74f8d
Binary files /dev/null and b/VectPotential.txt.identcache differ
diff --git a/VectPotential_Icon.ico b/VectPotential_Icon.ico
new file mode 100644
index 0000000..9d0e1f3
Binary files /dev/null and b/VectPotential_Icon.ico differ
diff --git a/VectorPotential.dcu b/VectorPotential.dcu
new file mode 100644
index 0000000..68a20cf
Binary files /dev/null and b/VectorPotential.dcu differ
diff --git a/VectorPotential.ddp b/VectorPotential.ddp
new file mode 100644
index 0000000..4370276
Binary files /dev/null and b/VectorPotential.ddp differ
diff --git a/VectorPotential.dfm b/VectorPotential.dfm
new file mode 100644
index 0000000..0184a88
Binary files /dev/null and b/VectorPotential.dfm differ
diff --git a/VectorPotential.pas b/VectorPotential.pas
new file mode 100644
index 0000000..08605a9
--- /dev/null
+++ b/VectorPotential.pas
@@ -0,0 +1,7316 @@
+// VectPotential - 3D wave modelling platform.
+//
+// (c) Copyright 1998 - 2020 : Declan Traill
+//
+// For the Theory behind this model, see the following papers:
+//
+// https://www.researchgate.net/publication/326646134_Wave_functions_for_the_electron_and_positron
+//
+// https://www.researchgate.net/publication/342025994_Charged_particle_attraction_and_repulsion_explained_A_detailed_mechanism_based_on_particle_wave-functions
+//
+// https://www.researchgate.net/publication/343206825_Electron_Wave_Function_-_Rest_Energy_Calculation
+//
+unit VectorPotential;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
+ ExtCtrls, StdCtrls, Spin, ComCtrls, Math, Grids, Jpeg;
+
+const
+ STANDING_WAVE_ANALYSIS=false;
+ TWO_PARTICLE_REFLECTION_FIELDS=true;
+
+ // Number of points to divide by in vector functions across point groups
+ nP=3;
+
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ GRID_LIMIT=270;
+{$ELSE}
+ GRID_LIMIT=280;
+{$IFEND}
+
+{$IF STANDING_WAVE_ANALYSIS}
+ GRID_SIZE=100;
+{$ELSE}
+ GRID_SIZE=100;
+{$IFEND}
+
+type {Type declaration for a vector resolved into x,y & z components}
+
+{$IF STANDING_WAVE_ANALYSIS}
+ FloatVar=single;
+{$ELSE}
+ FloatVar=single;
+{$IFEND}
+
+ Vector = record
+ x: FloatVar;
+ y: FloatVar;
+ z: FloatVar;
+ end;
+
+ VectorGrp = record
+ V0: Vector;
+ V1: Vector;
+ V2: Vector;
+ V3: Vector;
+ V4: Vector;
+ V5: Vector;
+ V6: Vector;
+ end;
+
+ ScalarGrp = record
+ S0: FloatVar;
+ S1: FloatVar;
+ S2: FloatVar;
+ S3: FloatVar;
+ S4: FloatVar;
+ S5: FloatVar;
+ S6: FloatVar;
+ end;
+
+ point = record {Type declaration for a grid point}
+ PsiVect: Vector;
+ Psi: FloatVar;
+ Hertzian: Vector;
+ Hertzian_scalar: Vector;
+ ElectricPotential: FloatVar;
+ VectorPotential: Vector;
+ Electric: Vector;
+ Magnetic: Vector;
+ ChargeDensity: FloatVar;
+ PsiCurlVect: Vector;
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ particle_pos_Reflected: Vector;
+ particle_neg_Reflected: Vector;
+{$IFEND}
+ end;
+
+ PointGrp = record
+ P0: point;
+ P1: point;
+ P2: point;
+ P3: point;
+ P4: point;
+ P5: point;
+ P6: point;
+ end;
+
+ Analysis_Values = record
+ power_sum1: extended;
+ power_sum2: extended;
+ reflected_sum: extended;
+ power_opposed_1_sum1: extended;
+ power_opposed_1_sum2: extended;
+ power_opposed_2_sum1: extended;
+ power_opposed_2_sum2: extended;
+ power_reflected_1_sum1: extended;
+ power_reflected_1_sum2: extended;
+ power_reflected_2_sum1: extended;
+ power_reflected_2_sum2: extended;
+ power_aligned_1_sum1: extended;
+ power_aligned_1_sum2: extended;
+ power_aligned_2_sum1: extended;
+ power_aligned_2_sum2: extended;
+ avg_power_opposed_1_sum1: extended;
+ avg_power_opposed_1_sum2: extended;
+ avg_power_opposed_2_sum1: extended;
+ avg_power_opposed_2_sum2: extended;
+ avg_power_reflected_1_sum1: extended;
+ avg_power_reflected_1_sum2: extended;
+ avg_power_reflected_2_sum1: extended;
+ avg_power_reflected_2_sum2: extended;
+ avg_power_aligned_1_sum1: extended;
+ avg_power_aligned_1_sum2: extended;
+ avg_power_aligned_2_sum1: extended;
+ avg_power_aligned_2_sum2: extended;
+ accel_1: extended;
+ accel_2: extended;
+ accel_3: extended;
+ accel_4: extended;
+ accel_5: extended;
+ accel_6: extended;
+ accel_avg: extended;
+ end;
+
+ PointPtr = ^point; {Define a type: pointer to a grid point}
+ BitmapPtr = ^TBitmap; {Define a type: pointer to a bitmap}
+ TColorPtr = ^TColor; {Define a type: pointer to a 24 bit colour type (TColor)}
+
+ EdgeMasks = array[1..9,1..3,1..3] of byte; {Define the EdgeMasks array type}
+
+ TForm1 = class(TForm)
+ StartGroup: TGroupBox;
+ Start1: TRadioButton;
+ Start2: TRadioButton;
+ start3: TRadioButton;
+ Start4: TRadioButton;
+ Start5: TRadioButton;
+ Start6: TRadioButton;
+ Start7: TRadioButton;
+ Start8: TRadioButton;
+ Start9: TRadioButton;
+ Start10: TRadioButton;
+ Start11: TRadioButton;
+ Start12: TRadioButton;
+ Start13: TRadioButton;
+ Start14: TRadioButton;
+ ZPlaneGroup: TGroupBox;
+ ZPlane: TTrackBar;
+ Z_Plane_Number: TEdit;
+ MainGroup: TGroupBox;
+ TimeDisplay: TEdit;
+ ReScale: TSpinEdit;
+ AmpDisplay: TEdit;
+ TimeFreeze: TButton;
+ Image1: TImage;
+ DisplayLevel: TScrollBar;
+ FieldGroup: TGroupBox;
+ Field1: TRadioButton;
+ Field2: TRadioButton;
+ Field3: TRadioButton;
+ Field4: TRadioButton;
+ Field5: TRadioButton;
+ StatsGroup: TGroupBox;
+ Energy1: TEdit;
+ Energy2: TEdit;
+ Energy3: TEdit;
+ Units1: TEdit;
+ Units2: TEdit;
+ Units3: TEdit;
+ Energy_Msg1: TEdit;
+ Energy_Msg2: TEdit;
+ Energy_Msg3: TEdit;
+ ColourGroup: TGroupBox;
+ ColourX_Group: TGroupBox;
+ ColourY_Group: TGroupBox;
+ ColourZ_Group: TGroupBox;
+ X_Red: TRadioButton;
+ X_Green: TRadioButton;
+ X_Blue: TRadioButton;
+ Y_Red: TRadioButton;
+ Y_Green: TRadioButton;
+ Y_Blue: TRadioButton;
+ Z_Red: TRadioButton;
+ Z_Green: TRadioButton;
+ Z_Blue: TRadioButton;
+ X_Colour: TImage;
+ Y_Colour: TImage;
+ Z_Colour: TImage;
+ DisplayOptionsGroup: TGroupBox;
+ RendDisplay: TCheckBox;
+ Vect_Arrows: TCheckBox;
+ Vector_Group: TGroupBox;
+ VectorX: TCheckBox;
+ VectorY: TCheckBox;
+ VectorZ: TCheckBox;
+ Spacing_Text: TStaticText;
+ Spacing_metres: TRadioButton;
+ Spacing_pixels: TRadioButton;
+ Bevel1: TBevel;
+ FirstZ: TStaticText;
+ LastZ: TStaticText;
+ Z_Tiling: TButton;
+ TileGrid: TDrawGrid;
+ GridGroup: TGroupBox;
+ GridX: TEdit;
+ GridY: TEdit;
+ GridZ: TEdit;
+ GridXlabel: TLabel;
+ GridYlabel: TLabel;
+ GridZlabel: TLabel;
+ RendGroup: TGroupBox;
+ AspectControl: TCheckBox;
+ AcceptGridSize: TButton;
+ GreyscaleButton: TRadioButton;
+ ColourButton: TRadioButton;
+ X_grey: TRadioButton;
+ Y_grey: TRadioButton;
+ Z_grey: TRadioButton;
+ AutoWarnTimer: TTimer;
+ Timesteps: TSpinEdit;
+ Label1: TLabel;
+ RateOfTime: TScrollBar;
+ Label2: TLabel;
+ GroupBox2: TGroupBox;
+ CheckBox1: TCheckBox;
+ CheckBox2: TCheckBox;
+ Spacing_gridpoints: TRadioButton;
+ Button1: TButton;
+ VectorSpacing: TEdit;
+ RenderOption1: TRadioButton;
+ RenderOption2: TRadioButton;
+ RenderOption3: TRadioButton;
+ ArrowScaleScroll: TScrollBar;
+ Label3: TLabel;
+ ActualGridWidth: TEdit;
+ Label4: TLabel;
+ Label5: TLabel;
+ Button2: TButton;
+ ViewFromTop: TCheckBox;
+ AutoScaleGroup: TGroupBox;
+ AutoWarn: TImage;
+ Auto1: TRadioButton;
+ Auto2: TRadioButton;
+ Auto3: TRadioButton;
+ Auto4: TRadioButton;
+ Scale_3D: TCheckBox;
+ field6: TRadioButton;
+ Field7: TRadioButton;
+ Field8: TRadioButton;
+ Field9: TRadioButton;
+ CheckBox3: TCheckBox;
+ RadioButton1: TRadioButton;
+ Y_none: TRadioButton;
+ X_none: TRadioButton;
+ Z_none: TRadioButton;
+ Edit1: TEdit;
+ Energy4: TEdit;
+ Edit2: TEdit;
+ SmoothingCheckBox: TCheckBox;
+ Field10: TRadioButton;
+ Start15: TRadioButton;
+ Start16: TRadioButton;
+ Start17: TRadioButton;
+ EnergyCorrectionCheckBox: TCheckBox;
+ Start18: TRadioButton;
+ Start19: TRadioButton;
+ Start20: TRadioButton;
+ CheckBox4: TCheckBox;
+ CheckBox5: TCheckBox;
+ CheckBox6: TCheckBox;
+ CheckBox7: TCheckBox;
+ CheckBox8: TCheckBox;
+ CheckBox9: TCheckBox;
+ CheckBox10: TCheckBox;
+ CheckBox11: TCheckBox;
+ CheckBox12: TCheckBox;
+ HFormulaCheckBox: TCheckBox;
+ EFormulaCheckBox: TCheckBox;
+ Start21: TRadioButton;
+ Start22: TRadioButton;
+ Start23: TRadioButton;
+ DistBetween: TEdit;
+ DistBetweenUnits: TLabel;
+ DistBetweenLabel: TLabel;
+ Field11: TRadioButton;
+ Field12: TRadioButton;
+ Profile_GroupBox: TGroupBox;
+ Profile_RadioButton_Off: TRadioButton;
+ Profile_RadioButton_GridSize: TRadioButton;
+ Profile_RadioButton_Distance: TRadioButton;
+ Profile_RadioButton_ActualSize: TRadioButton;
+ ShowEnergy_CheckBox: TCheckBox;
+ ProgressBar1: TProgressBar;
+ Percent_c: TLabel;
+ Start24: TRadioButton;
+ Start25: TRadioButton;
+ Start26: TRadioButton;
+ Start27: TRadioButton;
+ Start28: TRadioButton;
+ procedure FormCreate(Sender: TObject);
+ procedure Start1Click(Sender: TObject);
+ procedure Start2Click(Sender: TObject);
+ procedure Field0Click(Sender: TObject);
+ procedure Field1Click(Sender: TObject);
+ procedure Field2Click(Sender: TObject);
+ procedure Field3Click(Sender: TObject);
+ procedure Field4Click(Sender: TObject);
+ procedure Field5Click(Sender: TObject);
+ procedure Field6Click(Sender: TObject);
+ procedure Field7Click(Sender: TObject);
+ procedure Field8Click(Sender: TObject);
+ procedure Field9Click(Sender: TObject);
+ procedure Field10Click(Sender: TObject);
+ procedure Field11Click(Sender: TObject);
+ procedure Field12Click(Sender: TObject);
+ procedure start3Click(Sender: TObject);
+ procedure Start4Click(Sender: TObject);
+ procedure Start5Click(Sender: TObject);
+ procedure Start6Click(Sender: TObject);
+ procedure Start7Click(Sender: TObject);
+ procedure Start8Click(Sender: TObject);
+ procedure Start9Click(Sender: TObject);
+ procedure Start10Click(Sender: TObject);
+ procedure Start11Click(Sender: TObject);
+ procedure Start12Click(Sender: TObject);
+ procedure Start13Click(Sender: TObject);
+ procedure Start14Click(Sender: TObject);
+ procedure Start15Click(Sender: TObject);
+ procedure Start16Click(Sender: TObject);
+ procedure Start17Click(Sender: TObject);
+ procedure Start18Click(Sender: TObject);
+ procedure Start19Click(Sender: TObject);
+ procedure Start20Click(Sender: TObject);
+ procedure Start21Click(Sender: TObject);
+ procedure Start22Click(Sender: TObject);
+ procedure Start23Click(Sender: TObject);
+ procedure Start24Click(Sender: TObject);
+ procedure Start25Click(Sender: TObject);
+ procedure Start26Click(Sender: TObject);
+ procedure Start27Click(Sender: TObject);
+ procedure Start28Click(Sender: TObject);
+ procedure TimeFreezeClick(Sender: TObject);
+ procedure ZPlaneChange(Sender: TObject);
+ procedure DisplayLevelChange(Sender: TObject);
+ procedure ReScaleChange(Sender: TObject);
+ procedure X_RedClick(Sender: TObject);
+ procedure X_GreenClick(Sender: TObject);
+ procedure X_BlueClick(Sender: TObject);
+ procedure X_greyClick(Sender: TObject);
+ procedure Y_RedClick(Sender: TObject);
+ procedure Y_GreenClick(Sender: TObject);
+ procedure Y_BlueClick(Sender: TObject);
+ procedure Y_greyClick(Sender: TObject);
+ procedure Z_RedClick(Sender: TObject);
+ procedure Z_GreenClick(Sender: TObject);
+ procedure Z_BlueClick(Sender: TObject);
+ procedure Z_greyClick(Sender: TObject);
+ procedure GreyscaleButtonClick(Sender: TObject);
+ procedure ColourButtonClick(Sender: TObject);
+ procedure Auto1Click(Sender: TObject);
+ procedure Auto2Click(Sender: TObject);
+ procedure Auto3Click(Sender: TObject);
+ procedure Auto4Click(Sender: TObject);
+ procedure Vect_ArrowsClick(Sender: TObject);
+ procedure VectorSpacingChange(Sender: TObject);
+ procedure Z_TilingClick(Sender: TObject);
+ procedure Image1Click(Sender: TObject);
+ procedure Image1DblClick(Sender: TObject);
+ procedure VectorXClick(Sender: TObject);
+ procedure VectorYClick(Sender: TObject);
+ procedure VectorZClick(Sender: TObject);
+ procedure Spacing_pixelsClick(Sender: TObject);
+ procedure Spacing_metresClick(Sender: TObject);
+ procedure Spacing_gridpointsClick(Sender: TObject);
+ procedure RenderOption1Click(Sender: TObject);
+ procedure RenderOption2Click(Sender: TObject);
+ procedure RenderOption3Click(Sender: TObject);
+ procedure RendDisplayClick(Sender: TObject);
+ procedure AspectControlClick(Sender: TObject);
+ procedure GridXChange(Sender: TObject);
+ procedure GridYChange(Sender: TObject);
+ procedure GridZChange(Sender: TObject);
+ procedure FormDestroy(Sender: TObject);
+ procedure AcceptGridSizeClick(Sender: TObject);
+ procedure X_noneClick(Sender: TObject);
+ procedure Y_noneClick(Sender: TObject);
+ procedure Z_noneClick(Sender: TObject);
+ procedure AutoWarnTimerTimer(Sender: TObject);
+ procedure FormClose(Sender: TObject; var Action: TCloseAction);
+ procedure RateOfTimeChange(Sender: TObject);
+ procedure CheckBox1Click(Sender: TObject);
+ procedure CheckBox2Click(Sender: TObject);
+ procedure CheckBox3Click(Sender: TObject);
+ procedure Button1Click(Sender: TObject);
+ procedure ArrowScaleScrollChange(Sender: TObject);
+ procedure Button2Click(Sender: TObject);
+ procedure ViewFromTopClick(Sender: TObject);
+ procedure Scale_3DClick(Sender: TObject);
+ procedure SmoothingCheckBoxClick(Sender: TObject);
+ procedure EnergyCorrectionCheckBoxClick(Sender: TObject);
+ procedure EFormulaCheckBoxClick(Sender: TObject);
+ procedure HFormulaCheckBoxClick(Sender: TObject);
+ procedure CheckBox12Click(Sender: TObject);
+ procedure ActualGridWidthChange(Sender: TObject);
+ procedure DistBetweenChange(Sender: TObject);
+ procedure Profile_RadioButton_OffClick(Sender: TObject);
+ procedure Profile_RadioButton_GridSizeClick(Sender: TObject);
+ procedure Profile_RadioButton_DistanceClick(Sender: TObject);
+ procedure Profile_RadioButton_ActualSizeClick(Sender: TObject);
+ private
+ { Private declarations }
+ procedure WMSysCommand (var Msg: TWMSysCommand) ; message WM_SYSCOMMAND;
+ public
+ procedure Propagate;
+ procedure ProfileCancel;
+ procedure Initialise(first:boolean);
+ procedure update_progress_bar(progress:single);
+ procedure RecalcFields(scr:smallint);
+ procedure UpdateBitmap(scr:smallint);
+ procedure DisplayScreen(scr:smallint);
+ function sign(number: extended): shortint;
+ function Gauss(x: extended): extended;
+ procedure UpdateDetails;
+ procedure UpdateAxisColours(which: string);
+ procedure Auto_Scale(scr: smallint);
+ procedure MaxCheck(element: PointPtr);
+ function VectSize(vect: Vector): extended;
+ function BtoH(Bvect: Vector): Vector;
+ function E_Energy(E_vect: Vector): extended;
+ function B_Energy(B_vect: Vector): extended;
+ procedure DrawArrow(ThisBitmap: Tbitmap;x,y: smallint; arrow: Vector);
+ procedure NewBitmap(BmapPtr: BitmapPtr);
+ procedure PlotPoint(Bmap: TBitmap; x, y: smallint);
+ function RGB_Val(colour: Tcolor; primary: integer): byte;
+ function EdgeCase(x, y, Xmin, Ymin, Xmax, Ymax: smallint): byte;
+ function VectorInterpolate(v1, v2, v3, v4: Vector; Xfrac,
+ Yfrac: extended): Vector;
+ function Interpolate(val1, val2, val3, val4, Xfrac,
+ Yfrac: extended): extended;
+ procedure PlotQuadrant(Bmap: TBitmap; Quadrant: byte; RealX, RealY: extended);
+ function GetActualX(x: smallint): smallint;
+ function GetActualY(y: smallint): smallint;
+ procedure SetTileSize;
+ function Round2(realval: extended): int64;
+ function GetRealX(x: extended): extended;
+ function GetRealY(y: extended): extended;
+ function ColourRange(value: extended; ScaleFactor: extended): byte;
+ function VectToColours(vect: vector; ScaleFactor: extended): vector;
+ function ByteLimit(value: extended): smallint;
+ function VectByteLimit(vect: Vector): Vector;
+ function VectorCross(v1, v2: Vector): Vector;
+ function PowerFlow(Apoint: point): vector;
+ function RMS_PowerFlow(Apoint: point): vector;
+ function VectorProperty(field: byte; Apoint: point): vector;
+ function PointNull(Apoint: point; DisplayField: smallint): boolean;
+ function VectorNull(vect: Vector): boolean;
+ function ReverseTColor(input: TColor): Tcolor;
+ function MouseZplane: smallint;
+ procedure TileCursor(Bmap: TBitmap; Tile: smallint; colour: TColor);
+ procedure PlotPixel(x, y: smallint; Colour: TColor);
+ procedure UpdateE_Energy(scr: smallint);
+ procedure UpdateB_Energy(scr: smallint);
+ procedure SetAspectRatio;
+ procedure SetGridGlobals;
+ procedure ReAllocGridMemory;
+ function VectDiv(VectGroup: VectorGrp): extended;
+ function VectCurl(VectGroup: VectorGrp): Vector;
+ function PointGroup(scr, x, y, z: smallint): PointGrp;
+ function VectorGroup(PntGroup: PointGrp; Field: smallint): VectorGrp;
+ function ScalarGroup(PntGroup: PointGrp; Field: smallint): ScalarGrp;
+ function IntegrateScalarGrp(ScalarGroup: ScalarGrp): extended;
+ function IsVectorField(Field: smallint): boolean;
+ procedure FindMaxVal(scr, Field: smallint);
+ procedure FindAverageVal(scr, Field: smallint);
+ function VectorDot(v1, v2: Vector): extended;
+ function Normalize(v: Vector): Vector;
+ function ScalarGrad(ScalarGroup: ScalarGrp): Vector;
+ { Public declarations }
+ end;
+
+ procedure ProcSetGridGlobals(Form: TForm1);
+
+const
+{EdgeArray is an array used to determine which points exist within the range of}
+{a rectangular region (such as a grid x/y plane) given a known edge condition}
+{The edge condition is determined elsewhere by EdgeCase; its values range from}
+{1 to 9 corresponding to the point in question residing at the topleft corner,}
+{somewhere along the top edge, the topright corner... etc.}
+{The values in the sub-arrays indicate which of the points surrounding the }
+{point in question are in range: 1=in range, 0=out of range}
+
+ EdgeArray : EdgeMasks = (((0,0,0), {Top Left corner}
+ (0,1,1),
+ (0,1,1)),
+
+ ((0,0,0), {Top Edge}
+ (1,1,1),
+ (1,1,1)),
+
+ ((0,0,0), {Top Right Corner}
+ (1,1,0),
+ (1,1,0)),
+
+ ((0,1,1), {Left Edge}
+ (0,1,1),
+ (0,1,1)),
+
+ ((1,1,1), {Not on an Edge or Corner}
+ (1,1,1),
+ (1,1,1)),
+
+ ((1,1,0), {Right Edge}
+ (1,1,0),
+ (1,1,0)),
+
+ ((0,1,1), {Bottom Left Corner}
+ (0,1,1),
+ (0,0,0)),
+
+ ((1,1,1), {Bottom Edge}
+ (1,1,1),
+ (0,0,0)),
+
+ ((1,1,0), {Bottom Right Corner}
+ (1,1,0),
+ (0,0,0)));
+
+ StartOptionCaptions : array[1..28] of String = (
+ ('1: e'),
+ ('2: p'),
+ ('3: ee^^'),
+ ('4: pp^^'),
+ ('5: ep^^'),
+ ('6: ee^>'),
+ ('7: pp^>'),
+ ('8: ep^>'),
+ ('9: ee^<'),
+ ('10: pp^<'),
+ ('11: ep^<'),
+ ('12: ee>>'),
+ ('13: pp>>'),
+ ('14: ep>>'),
+ ('15: ee><'),
+ ('16: pp><'),
+ ('17: ep><'),
+ ('18: ee^v'),
+ ('19: pp^v'),
+ ('20: ep^v'),
+ ('21: e OUT'),
+ ('22: e IN'),
+ ('23: e BOTH'),
+ ('24: Proton'),
+ ('25: Neutron'),
+ ('26: Neutrino'),
+ ('27: U Quark'),
+ ('28: D Quark')
+ );
+const
+
+ Default_GridWidth=GRID_SIZE; {Default Number of Pixels wide}
+ Default_GridHeight=GRID_SIZE; {Default Number of Pixels high}
+ Default_GridDepth=GRID_SIZE; {Default Number of Pixels Deep}
+
+ RATE_OF_TIME_DIVISOR=1E17;
+ SpeedOfLight=2.99792458E8; {Speed of Light in meters per second}
+ Permittivity= 8.8541878176E-12; {Permittivity of free space (farad/m)}
+ Permeability=4*Pi*1E-7; {Permeability of free space (Henry/m)}
+ Hhat=1.054571596E-34; {reduced Planck's constant}
+ Ek=8.9875517873681764e9; {Coulomb's constant}
+ alpha=0.007297352569311; {Fine Structure Constant}
+
+ UnitaryCharge=1.60217662E-19;
+ ElectronCharge=-UnitaryCharge;
+ PositronCharge=UnitaryCharge;
+ ProtonCharge=UnitaryCharge;
+ NeutronCharge=0;
+
+ PositronMass=9.1093835611E-31; // (8.187105650638658873144497804e-14 Joules)
+
+ ElectronMass=9.1093835611E-31; // (8.187105650638658873144497804e-14 Joules)
+ ElectronComptonWavelength=2*Pi*Hhat/(ElectronMass*SpeedOfLight); // 2.4263097661e-12
+ ElectronComptonRadius=ElectronComptonWavelength/(2*Pi); // 3.8615919275e-13
+ ElectronClassicalRadius=alpha*ElectronComptonRadius; // 2.8179397774e-15
+
+ ProtonMass=1.6726219E-27; // (1.503277594693615520970316e-10 Joules)
+ ProtonComptonWavelength=2*Pi*Hhat/(ProtonMass*SpeedOfLight); // 1.3214095964e-15
+ ProtonComptonRadius=ProtonComptonWavelength/(2*Pi); // 2.1030886911e-16
+ ProtonClassicalRadius=alpha*ProtonComptonRadius; // 1.5346979664e-18
+
+ NeutronMass=1.6749274980495E-27; // (1.50534976288068915159493719318e-10 Joules)
+ NeutronComptonWavelength=2*Pi*Hhat/(NeutronMass*SpeedOfLight); // 1.3195906285e-15
+ NeutronComptonRadius=NeutronComptonWavelength/(2*Pi); // 2.1001937138e-16
+ NeutronClassicalRadius=alpha*ProtonComptonRadius; // 1.5346979664e-18
+
+ ElectronNeutrinoMass=1.17726E-35;// (1.0580685217197059348664e-18 Joules)
+ ElectronNeutrinoComptonWavelength=2*Pi*Hhat/(ElectronNeutrinoMass*SpeedOfLight); // 1.8774260824e-07
+ ElectronNeutrinoComptonRadius=ElectronNeutrinoComptonWavelength/(2*Pi); // 2.988016413e-08
+ ElectronNeutrinoClassicalRadius=alpha*ElectronNeutrinoComptonRadius; // 2.1804609249e-10
+
+ UpQuarkMass=((1/4)*ProtonMass);
+
+ DownQuarkMass=((1/2)*ProtonMass);
+
+ Max_E=0; {Max value of Electric field to allow per pixel - Volts/m (0 value disables it)}
+ Max_B=0; {Max value of Magnetic field to allow per pixel - Tesla (0 value disables it)}
+
+ RED=$1; {Multiplication factor for 4-byte RGB colour}
+ GREEN=$100; {Multiplication factor for 4-byte RGB colour}
+ BLUE=$10000; {Multiplication factor for 4-byte RGB colour}
+ GREY=$7F7F7F;{Definition for white}
+ BLACK=$0; {Definition for black}
+ RedMask=$FF; {Masking value for colour separation}
+ GreenMask=$FF00; {Masking value for colour separation}
+ BlueMask=$FF0000; {Masking value for colour separation}
+ START=1; {AutoScaling constants}
+ CONTINUAL=2; {AutoScaling constants}
+ NEVER=3; {AutoScaling constants}
+ AVERAGE=4; {AutoScaling constants}
+ OneToOne=1; {Rendering Option Constant - for 1 pixel per point}
+ Chunky=2; {Rendering Option Constant - for filled rectangle per point}
+ Blend=3; {Rendering Option Constant - colour blending betweem points}
+ EdgeSize=3; {Size of border between Tiled Z Planes & screen edge}
+
+ PSI_VECTOR_FIELD=0;
+ PSI_SCALAR_FIELD=1;
+ ELECTRIC_POTENTIAL_FIELD=2;
+ HERTZIAN_FIELD=3;
+ VECTOR_POTENTIAL_FIELD=4;
+ ELECTRIC_FIELD=5;
+ MAGNETIC_FIELD=6;
+ E_ELECTRIC_FIELD=7;
+ E_MAGNETIC_FIELD=8;
+ POWER_FLOW_FIELD=9;
+ CHARGE_DENSITY_FIELD=10;
+ PSI_CURL_VECTOR_FIELD=11;
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PARTICLE_POS_REFLECTED_FIELD=12;
+ PARTICLE_NEG_REFLECTED_FIELD=13;
+{$IFEND}
+
+type
+ { Create the array type }
+ TDynamicArray = array of array of array of point; {[1..GridWidth,1..GridHeight,1..GridDepth] of point;}
+ pointsPtr = ^TDynamicArray;
+var
+ Form1: TForm1;
+ Bitmap1,Bitmap2: TBitmap;
+ BitmapRed,BitmapGreen,BitmapBlue,BitmapGrey,BitmapBlack: TBitmap;
+
+ // Note: the Grid (0,0,0) point is at the Top, Left & Back point of the Grid
+ // So X increments to the right, Y increments downwards, & Z increments out of the screen
+ PPMx, PPMy, PPMz: Extended;
+ points1: TDynamicArray;
+// points2: TDynamicArray;
+ points: array[0..0] of pointsPtr;
+ particle1_A: array of array of array of Vector;
+ particle2_A: array of array of array of Vector;
+ particle1_E: array of array of array of Vector;
+ particle2_E: array of array of array of Vector;
+ particle_1_2_B: array of array of array of Vector;
+ particle1_Power: array of array of array of Vector;
+ particle2_Power: array of array of array of Vector;
+ analysis_results: array[1..18] of array[0..50] of Analysis_Values;
+ ColourArray: array of array of TColor; {[1..GridWidth,1..GridHeight] of Tcolor;}
+ SignArray: array of array of array of shortint; {[1..GridWidth,1..GridHeight,1..3] of shortint;}
+ ColArray: array[1..9] of Tcolor;
+ PntArray: array[1..9] of Vector;
+ YLinePtrs: array of PByteArray;
+ GridWidth,GridHeight,GridDepth: integer;
+ New_GridWidth,New_GridHeight,New_GridDepth: integer;
+ screen: smallint;
+ StartOption,New_StartOption: smallint;
+ New_DisplayField,DisplayField : smallint;
+ Time,TimeStep : extended;
+ RescaleFactor, New_ReScale : double;
+ Z_Plane, New_ZPlane : smallint;
+ FreezeTime, New_FreezeTime: Boolean;
+ TileZ, New_TileZ: Boolean;
+ ShowColour, New_ShowColour: Boolean;
+ IsGrey,DoUpdate : Boolean;
+ E_Energy_Tot,B_Energy_Tot,Etotal,MaxVal : extended;
+ Amplification : extended;
+ X_RGB,Y_RGB,Z_RGB : Tcolor;
+ New_AutoScale,AutoScale: smallint;
+ ZplanePos,OriginX,OriginY : smallint;
+ FirstPass : boolean;
+ ArrowScale: extended;
+ ScrScaleX,ScrScaleY,HalfX,HalfY : extended;
+ BitmapX,BitmapY: smallint;
+ TileX,TileY,TileXcount,TileYcount : smallint;
+ Aspect: extended;
+ NullVect: Vector;
+ NullPoint: Point;
+ NullVectGrp: VectorGrp;
+ NullScalarGrp: ScalarGrp;
+ NullPointGrp: PointGrp;
+ MyMouse: TMouse;
+ AxisColours,New_AxisColours: string;
+ Display_Level,New_DisplayLevel: integer;
+ Rate_Of_Time,New_RateOfTime: integer;
+ Arrows, New_Arrows: boolean;
+ UpdateColours,ReDraw: boolean;
+ CurrentBitmap: TBitmap;
+ New_Render,Render: smallint;
+ New_Rendered,Rendered: boolean;
+ New_VectSpacing,VectSpacing: integer;
+ TileScrScaleX,TileScrScaleY: double;
+ TileHalfX,TileHalfY: extended;
+ MaintainAspect,New_MaintainAspect,VectorChange: boolean;
+ ActualWidth,ActualHeight,ActualDepth: extended;
+ PointArea,PointVolume: extended;
+ ScreenAspect: extended;
+ dx,dy,dz: extended;
+ ArrowsUnitsChange,AutoWarnState: boolean;
+ TileRect: TRect;
+ Quit: boolean;
+ Timestep_count: smallint;
+ FrameCount: integer;
+ save_frames,save_3D,New_Flip_YZ,Flip_YZ: boolean;
+ arrow_step: extended;
+ New_ArrowScaleFactor: integer;
+ ArrowScaleFactor: extended;
+ Restart, StartOptionChanged: boolean;
+ ViewTop: boolean;
+ AllFields: boolean;
+ smoothing: boolean;
+ two_particles: boolean;
+ particle1_x, particle2_x, p1_p2_diff : extended;
+ Velocity: Extended;
+ accel_avg, PercentBetweenParticles: extended;
+ IterationCount: integer;
+ EnergyCorrection: boolean;
+ E_useFormula, H_useFormula: boolean;
+ NumGridPoints: Extended;
+ two_particle_analysis, two_particle_accel_profile_done, profile_changed: boolean;
+ two_particle_accel_profile, two_particle_accel_dist_profile, two_particle_accel_actual_width_profile: boolean;
+ myFile, myFile2 : TextFile;
+ justRestored: boolean;
+implementation
+
+{$R *.DFM}
+{$G-} {Disable Data Importation from Units - Improves Memory access efficiency}
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+ Initialise(true);
+ Propagate();
+end;
+
+procedure TForm1.WMSysCommand(var Msg: TWMSysCommand) ;
+begin
+ if Msg.CmdType = SC_RESTORE then justRestored:=true;
+
+ DefaultHandler(Msg) ;
+end;
+
+function IsOpen(const txt:TextFile):Boolean;
+const
+ fmTextOpenRead = 55217;
+ fmTextOpenWrite = 55218;
+begin
+ Result := (TTextRec(txt).Mode = fmTextOpenRead) or (TTextRec(txt).Mode = fmTextOpenWrite)
+end;
+
+procedure TForm1.Initialise(first:boolean);
+var
+ scr,i,j,k : smallint;
+begin
+ if first then begin
+ points[0] := @points1;
+// points[1] := @points2;
+
+ two_particles:=false;
+ Restart:=true;
+ StartOptionChanged:=true;
+ FreezeTime:=false;
+ New_FreezeTime:=false;
+ StartOption:=1; {default to start config 3}
+ New_StartOption:=StartOption;
+ MyMouse:=TMouse.Create; {Create a mouse variable}
+ BitmapX:=Image1.Width; {get width of picture control on the form}
+ BitmapY:=Image1.Height; {get height of picture control on the form}
+ ScreenAspect:=BitmapY/BitmapX; {Calc Screen's aspect ratio}
+ SetLength(YLinePtrs,BitmapY); {determine size for array of bitmap line pointers}
+ New_DisplayField:=PSI_VECTOR_FIELD; {set default to displaying the PSI_VECTOR_FIELD field}
+ NewBitmap(@Bitmap1); {create a new blank 24bit bitmap}
+ NewBitmap(@Bitmap2); {create a new blank 24bit bitmap}
+ BitmapRed := TBitmap.Create; {create a bitmap for the red square}
+ BitmapGreen := TBitmap.Create; {create a bitmap for the green square}
+ BitmapBlue := TBitmap.Create; {create a bitmap for the blue square}
+ BitmapGrey := TBitmap.Create; {create a bitmap for the grey square}
+ BitmapBlack := TBitmap.Create; {create a bitmap for the black square}
+ BitmapRed.LoadFromFile('red.bmp'); {load the red square from disk}
+ BitmapGreen.LoadFromFile('green.bmp'); {load the green square from disk}
+ BitmapBlue.LoadFromFile('blue.bmp'); {load the blue square from disk}
+ BitmapGrey.LoadFromFile('grey.bmp'); {load the blue square from disk}
+ BitmapBlack.LoadFromFile('black.bmp'); {load the black square from disk}
+
+ New_ShowColour:=true; {default to displaying a colour image}
+ AutoScale:=AVERAGE; {default autoscale option to at AVERAGE}
+ New_TileZ:=false; {default Z plane Tiling option}
+ New_Arrows:=true; {default to Vector Arrows On}
+ New_Render:=Blend; {default to Colour Blended Rendering}
+ New_Rendered:=true; {default to Rendered Display On}
+ New_DisplayLevel:=1995; {default Level slider to (2000 - n)*1000%}
+ New_RateOfTime:=RateOfTime.Position; {default Rate of Time slider}
+ New_MaintainAspect:=true; {Default Aspect Ratio Control setting}
+ New_AutoScale:=AVERAGE; {Default AutoScale option to AVERAGE}
+ GridWidth:=0; {Ensure a full update occurs}
+ GridHeight:=0;
+ GridDepth:=0;
+ New_GridWidth:=Default_GridWidth; {set default Grid Dimensions}
+ New_GridHeight:=Default_GridHeight;
+ New_GridDepth:=Default_GridDepth;
+ VectorChange:=false; {initialise flag}
+ New_Flip_YZ:=false;
+ Flip_YZ:=false;
+ New_ArrowScaleFactor := ArrowScaleScroll.Position;
+ ViewTop := ViewFromTop.Checked;
+
+ // Don't reset these if profiling - so frames can be captured of the whole profile if needed
+ if two_particle_accel_profile_done then begin
+ FrameCount:=1;
+ save_frames:=false;
+ save_3D:=false;
+ end;
+
+ if STANDING_WAVE_ANALYSIS then begin
+ StartOption:=20; {default to start config 18}
+ New_StartOption:=StartOption;
+// EnergyCorrectionCheckBox.Checked := false;
+ EnergyCorrection := EnergyCorrectionCheckBox.Checked;
+ ActualGridWidth.Text:='2.0E-11';
+ Start18.Visible:=true;
+ Start19.Visible:=true;
+ Start20.Visible:=true;
+ CheckBox4.Visible:=true;
+ CheckBox5.Visible:=true;
+ CheckBox6.Visible:=true;
+ CheckBox7.Visible:=true;
+ CheckBox8.Visible:=true;
+ CheckBox9.Visible:=true;
+ CheckBox10.Visible:=true;
+ CheckBox11.Visible:=true;
+ CheckBox12.Visible:=true;
+ end;
+ end;
+
+ ProcSetGridGlobals(Self);
+
+ Start1.Checked:=false;
+ Start2.Checked:=false;
+ Start3.Checked:=false;
+ Start4.Checked:=false;
+ Start5.Checked:=false;
+ Start6.Checked:=false;
+ Start7.Checked:=false;
+ Start8.Checked:=false;
+ Start9.Checked:=false;
+ Start10.Checked:=false;
+ Start11.Checked:=false;
+ Start12.Checked:=false;
+ Start13.Checked:=false;
+ Start14.Checked:=false;
+ Start15.Checked:=false;
+ Start16.Checked:=false;
+ Start17.Checked:=false;
+ Start18.Checked:=false;
+ Start19.Checked:=false;
+ Start20.Checked:=false;
+ Start21.Checked:=false;
+ Start22.Checked:=false;
+ Start23.Checked:=false;
+ Start24.Checked:=false;
+ Start25.Checked:=false;
+ Start26.Checked:=false;
+ Start27.Checked:=false;
+ Start28.Checked:=false;
+
+ case StartOption of
+ 1: begin // if electron being modelled
+ Start1.Checked:=true;
+ end;
+
+ 2: begin // if positron being modelled
+ Start2.Checked:=true;
+ end;
+
+ 3: begin // if two electrons being modelled
+ Start3.Checked:=true;
+ end;
+
+ 4: begin // if two positrons being modelled
+ Start4.Checked:=true;
+ end;
+
+ 5: begin // if an electron and a positron being modelled
+ Start5.Checked:=true;
+ end;
+
+ 6: begin // if two electrons being modelled
+ Start6.Checked:=true;
+ end;
+
+ 7: begin // if two positrons being modelled
+ Start7.Checked:=true;
+ end;
+
+ 8: begin // if an electron and a positron being modelled
+ Start8.Checked:=true;
+ end;
+
+ 9: begin // if two electrons being modelled
+ Start9.Checked:=true;
+ end;
+
+ 10: begin // if two positrons being modelled
+ Start10.Checked:=true;
+ end;
+
+ 11: begin // if an electron and a positron being modelled
+ Start11.Checked:=true;
+ end;
+
+ 12: begin // if an electron and a positron being modelled
+ Start12.Checked:=true;
+ end;
+
+ 13: begin // if an electron and a positron being modelled
+ Start13.Checked:=true;
+ end;
+
+ 14: begin // if an electron and a positron being modelled
+ Start14.Checked:=true;
+ end;
+
+ 15: begin // if an electron and a positron being modelled
+ Start15.Checked:=true;
+ end;
+
+ 16: begin // if an electron and a positron being modelled
+ Start16.Checked:=true;
+ end;
+
+ 17: begin // if an electron and a positron being modelled
+ Start17.Checked:=true;
+ end;
+
+ 18: begin // if an electron and a positron being modelled
+ Start18.Checked:=true;
+ end;
+
+ 19: begin // if an electron and a positron being modelled
+ Start19.Checked:=true;
+ end;
+
+ 20: begin // if an electron and a positron being modelled
+ Start20.Checked:=true;
+ end;
+
+ 21: begin // if electron OUT wave being modelled
+ Start21.Checked:=true;
+ end;
+
+ 22: begin // if electron IN wave being modelled
+ Start22.Checked:=true;
+ end;
+
+ 23: begin // if electron OUT+IN wave being modelled
+ Start23.Checked:=true;
+ end;
+
+ 24: begin // if proton being modelled
+ Start24.Checked:=true;
+ end;
+
+ 25: begin // if neutron being modelled
+ Start25.Checked:=true;
+ end;
+
+ 26: begin // if neutrino being modelled
+ Start26.Checked:=true;
+ end;
+
+ 27: begin // if Up Quark being modelled
+ Start27.Checked:=true;
+ end;
+
+ 28: begin // if Down Quark being modelled
+ Start28.Checked:=true;
+ end;
+ end;
+
+ with NullVect do begin
+ x:=0;
+ y:=0;
+ z:=0;
+ end;
+ with NullPoint do begin
+ Electric:=NullVect;
+ Magnetic:=NullVect;
+ end;
+ with NullVectGrp do begin
+ v0:=NullVect;
+ v1:=NullVect;
+ v2:=NullVect;
+ v3:=NullVect;
+ v4:=NullVect;
+ v5:=NullVect;
+ v6:=NullVect;
+ end;
+ with NullScalarGrp do begin
+ s0:=0;
+ s1:=0;
+ s2:=0;
+ s3:=0;
+ s4:=0;
+ s5:=0;
+ s6:=0;
+ end;
+ with NullPointGrp do begin
+ p0:=NullPoint;
+ p1:=NullPoint;
+ p2:=NullPoint;
+ p3:=NullPoint;
+ p4:=NullPoint;
+ p5:=NullPoint;
+ p6:=NullPoint;
+ end;
+ Form1.visible:=true; {show the Form (user interface)}
+ Image1.visible:=true; {ensure the Image is visible}
+ Screen:=0; {start by displaying bitmap1}
+ DisplayScreen(Screen); {make it visible}
+ New_DisplayLevel:=1995; {default Level slider to (2000 - n)*1000%}
+ Time:=0; {set time to zero}
+ Timestep_count:=0;
+ MaxVal:=0; {ensure MaxVal is zero}
+
+ // Don't reset these if profiling - so that they stay on the screen during profiling
+ if two_particle_accel_profile_done then begin
+ E_Energy_Tot:=0; {ensure Electric field energy total=0}
+ B_Energy_Tot:=0; {ensure Magnetic field energy total=0}
+ FrameCount:=1;
+ end;
+
+ Etotal:=0; {ensure integrated energy total=0}
+ New_AxisColours:='ALL'; {set axis colour display boxes to match selections}
+ UpdateDetails; {Update all changed values & displayed text}
+ DoUpdate:=false; {Initial conditions set up via FirstPass}
+ FirstPass:=true;
+ AllFields:=false;
+ accel_avg:=0;
+ IterationCount:=0;
+ EnergyCorrection := EnergyCorrectionCheckBox.Checked;
+ E_useFormula := EFormulaCheckBox.Checked;
+ H_useFormula := HFormulaCheckBox.Checked;
+
+ scr:=0;
+ if not first then {if first initialisation then Grid zero'ed already}
+ //for scr:=0 to 1 do {scan both copies of the grid's points}
+ for i:=0 to (GridWidth-2) do {and set all values to zero}
+ for j:=0 to (GridHeight-2) do
+ for k:=0 to (GridDepth-2) do begin
+ points[scr]^[i,j,k]:=NullPoint;
+ particle1_A[i,j,k]:=NullVect;
+ particle2_A[i,j,k]:=NullVect;
+ particle1_E[i,j,k]:=NullVect;
+ particle2_E[i,j,k]:=NullVect;
+ particle_1_2_B[i,j,k]:=NullVect;
+ particle1_Power[i,j,k]:=NullVect;
+ particle2_Power[i,j,k]:=NullVect;
+ end;
+ ReDraw:=true; {ensure redraw is enabled}
+end;
+
+function RunningAverage(old_count: integer; old_avg, new_value:extended): extended;
+begin
+ Result:= ((old_avg * old_count) + new_value) / (old_count + 1);
+end;
+
+procedure AnalysisWriteHeader();
+begin
+ // Write a couple of well known words to this file
+ WriteLn(myFile, 'Two Particle Analysis For StartOption ' + StartOptionCaptions[StartOption]);
+ WriteLn(myFile, '---------------------');
+ WriteLn(myFile, '');
+ WriteLn(myFile, '');
+end;
+
+
+procedure AnalysisSaveResults(StartOption: smallint; IterationCount: integer);
+begin
+ analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum1 := analysis_results[StartOption][IterationCount].power_opposed_1_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum2 := analysis_results[StartOption][IterationCount].power_opposed_1_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum1 := analysis_results[StartOption][IterationCount].power_opposed_2_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum2 := analysis_results[StartOption][IterationCount].power_opposed_2_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum1 := analysis_results[StartOption][IterationCount].power_reflected_1_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum2 := analysis_results[StartOption][IterationCount].power_reflected_1_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum1 := analysis_results[StartOption][IterationCount].power_reflected_2_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum2 := analysis_results[StartOption][IterationCount].power_reflected_2_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum1 := analysis_results[StartOption][IterationCount].power_aligned_1_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum2 := analysis_results[StartOption][IterationCount].power_aligned_1_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum1 := analysis_results[StartOption][IterationCount].power_aligned_2_sum1/NumGridPoints;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum2 := analysis_results[StartOption][IterationCount].power_aligned_2_sum2/NumGridPoints;
+ analysis_results[StartOption][IterationCount].accel_1 := analysis_results[StartOption][IterationCount].power_reflected_1_sum1 - analysis_results[StartOption][IterationCount].power_reflected_1_sum2 + analysis_results[StartOption][IterationCount].power_reflected_2_sum1 - analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_1 := analysis_results[StartOption][IterationCount].accel_1*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_2 := analysis_results[StartOption][IterationCount].power_reflected_1_sum1 - analysis_results[StartOption][IterationCount].power_reflected_1_sum2 - analysis_results[StartOption][IterationCount].power_reflected_2_sum1 + analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_2 := analysis_results[StartOption][IterationCount].accel_2*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_3 := -analysis_results[StartOption][IterationCount].power_reflected_1_sum1 + analysis_results[StartOption][IterationCount].power_reflected_1_sum2 + analysis_results[StartOption][IterationCount].power_reflected_2_sum1 - analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_3 := analysis_results[StartOption][IterationCount].accel_3*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_4 := -analysis_results[StartOption][IterationCount].power_reflected_1_sum1 + analysis_results[StartOption][IterationCount].power_reflected_1_sum2 - analysis_results[StartOption][IterationCount].power_reflected_2_sum1 + analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_4 := analysis_results[StartOption][IterationCount].accel_4*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_5 := analysis_results[StartOption][IterationCount].power_reflected_1_sum1 + analysis_results[StartOption][IterationCount].power_reflected_1_sum2 + analysis_results[StartOption][IterationCount].power_reflected_2_sum1 + analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_5 := analysis_results[StartOption][IterationCount].accel_5*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_6 := -analysis_results[StartOption][IterationCount].power_reflected_1_sum1 - analysis_results[StartOption][IterationCount].power_reflected_1_sum2 - analysis_results[StartOption][IterationCount].power_reflected_2_sum1 - analysis_results[StartOption][IterationCount].power_reflected_2_sum2;
+ analysis_results[StartOption][IterationCount].accel_6 := analysis_results[StartOption][IterationCount].accel_6*PointArea/(SpeedOfLight*ElectronMass);
+ analysis_results[StartOption][IterationCount].accel_avg := accel_avg;
+end;
+
+procedure AnalysisWriteResults(StartOption: smallint; IterationCount: integer);
+var
+ aligned_sum, opposed_sum, total_sum: extended;
+begin
+ aligned_sum:=analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum1 + analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum2 + analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum1 + analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum2;
+ opposed_sum:=analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum1 + analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum2 + analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum1 + analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum2;
+
+ WriteLn(myFile, 'avg_power_aligned_1_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum1));
+ WriteLn(myFile, 'avg_power_aligned_1_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum2));
+ WriteLn(myFile, 'avg_power_aligned_2_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum1));
+ WriteLn(myFile, 'avg_power_aligned_2_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum2));
+ WriteLn(myFile, 'avg_power_aligned_total: ' + FloatToStr(aligned_sum));
+ WriteLn(myFile, 'avg_power_opposed_1_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum1));
+ WriteLn(myFile, 'avg_power_opposed_1_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum2));
+ WriteLn(myFile, 'avg_power_opposed_2_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum1));
+ WriteLn(myFile, 'avg_power_opposed_2_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum1 + analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum2));
+ WriteLn(myFile, 'avg_power_opposed_total: ' + FloatToStr(opposed_sum));
+ WriteLn(myFile, 'avg_power_total: ' + FloatToStr(aligned_sum + opposed_sum));
+ WriteLn(myFile, 'avg_power_aligned_fraction: ' + FloatToStr(aligned_sum/(aligned_sum + opposed_sum)));
+ WriteLn(myFile, 'avg_power_opposed_fraction: ' + FloatToStr(opposed_sum/(aligned_sum + opposed_sum)));
+ WriteLn(myFile, 'avg_power_reflected_1_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum1));
+ WriteLn(myFile, 'avg_power_reflected_1_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum2));
+ WriteLn(myFile, 'avg_power_reflected_2_sum1: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum1));
+ WriteLn(myFile, 'avg_power_reflected_2_sum2: ' + FloatToStr(analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum2));
+ WriteLn(myFile, 'accel_1: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_1));
+ WriteLn(myFile, 'accel_2: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_2));
+ WriteLn(myFile, 'accel_3: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_3));
+ WriteLn(myFile, 'accel_4: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_4));
+ WriteLn(myFile, 'accel_5: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_5));
+ WriteLn(myFile, 'accel_6: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_6));
+ WriteLn(myFile, 'accel_avg: ' + FloatToStr(analysis_results[StartOption][IterationCount].accel_avg));
+ WriteLn(myFile, '');
+end;
+
+procedure TForm1.update_progress_bar(progress:single);
+begin
+ if progress > 100 then progress:=100;
+
+ ProgressBar1.Min := 0;
+ ProgressBar1.Max := 200;
+ ProgressBar1.Position := Round(2*progress);
+end;
+
+procedure TForm1.RecalcFields(scr:smallint);
+label
+ NeutronNext;
+var
+ r,r1,r2,x,y,z,unit_x,unit_y,unit_z,actual_x,actual_y,actual_z,r_lower_limit : extended;
+ theta, theta1, theta2, delta, delta1, delta2, theta_const, theta_const1, theta_const2, expTheta, lnTheta : extended;
+ term0, term1, term1a, term1b, term2, term2a, term2b, term3, term3a, term3b : extended;
+ psi_x, psi_y, psi_z, psi_x_particle1, psi_y_particle1, psi_z_particle1, psi_x_particle2, psi_y_particle2, psi_z_particle2 : extended;
+ normal_x,normal_y,normal_z,dir_x,dir_y,dir_z : extended;
+ scalar_amp, Vector_amp, SpinConstant, E_amp, A_amp : extended;
+ NewScreen : smallint;
+ xpos,ypos,zpos,midx,midy,midz:smallint;
+ ThisGroup,NewGroup: PointGrp;
+ vect,vect2,CurlVect,DivVect: vector;
+ Scalar_Group: ScalarGrp;
+ VectGrp: VectorGrp;
+ I: Integer;
+ ShellThickness: Extended;
+ dist: longint;
+ electron, positron, proton, neutron, neutrino, quark_up, quark_down: boolean;
+ orthogonal_particles: boolean;
+ particles_end_to_end: boolean;
+ particle1_spin, particle2_spin, saved_sign: integer;
+ pass, maxpass, n, x_sign: smallint;
+ AveragePowerPerPoint,ReflectedPowerAtPoint,PressurePerPoint,Force,Accel: Extended;
+ PowerSum_neg, PowerSum_pos, Pressure: Extended;
+ PowerCount_neg, PowerCount_pos: integer;
+ Power_x1, Power_x2, dot_v1v2, reflected_power: Extended;
+ PrevVectorPotential, ElecFieldFromV, ElecFieldFromA: Vector;
+ PowerCorrectionFactor_E, PowerCorrectionFactor_B, EnergyFactor: Extended;
+ ElectricPotentialSum_pos, ElectricPotentialSum_neg, ElectricPotentialSum: extended;
+ PsiSum, PsiSumXpos, PsiSumYpos, PsiSumZpos, PsiSumXneg, PsiSumYneg, PsiSumZneg: extended;
+ ElecFieldCurl_Sum, ElecFieldFromV_Sum, ElecFieldFromA_Sum, ElecField_Sum, MagField_Sum, VectorPotential_Sum : extended;
+ ElecFieldFromV_SignedHalf_SumX, ElecFieldFromA_SignedHalf_SumX : extended;
+ ElecFieldGradDivPsi_SignedHalf_SumX, ElecFieldCurlCurlPsi_SignedHalf_SumX :extended;
+ c1,c2,c3,A,DistFromCenter,ExpectedAccel,E_Energy_Sum,B_Energy_Sum: Extended;
+ field_stats: boolean;
+ sine_wave_sum, neutrino_quarklets: boolean;
+ progress, progress_inc, r_contracted, x_contracted, x_velocity, gamma, r_gamma, charge_sign, charge_factor: single;
+ Qsin1, Qcos1, Qsin2, Qcos2, M, c, E0: extended;
+
+begin
+ progress:=0;
+ progress_inc:=5.8;
+ update_progress_bar(progress);
+
+ NumGridPoints := (GridWidth*GridHeight*GridDepth);
+
+ field_stats:= false;
+
+ if two_particle_analysis then begin
+ if IterationCount = 0 then begin
+ // Try to open the Analysis.txt file for writing to
+ AssignFile(myFile, 'Analysis' + IntToStr(StartOption) + '.txt');
+ ReWrite(myFile);
+
+ AnalysisWriteHeader();
+ end;
+
+ WriteLn(myFile, 'StartOption: ' + IntToStr(StartOption) + ' Timestep: ' + IntToStr(IterationCount));
+ WriteLn(myFile, '');
+
+ analysis_results[StartOption][IterationCount].power_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_sum2:=0;
+ analysis_results[StartOption][IterationCount].reflected_sum:=0;
+ analysis_results[StartOption][IterationCount].power_opposed_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_opposed_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].power_opposed_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_opposed_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].power_reflected_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_reflected_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].power_reflected_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_reflected_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].power_aligned_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_aligned_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].power_aligned_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].power_aligned_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_opposed_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_reflected_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_1_sum2:=0;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum1:=0;
+ analysis_results[StartOption][IterationCount].avg_power_aligned_2_sum2:=0;
+ analysis_results[StartOption][IterationCount].accel_1:=0;
+ analysis_results[StartOption][IterationCount].accel_2:=0;
+ analysis_results[StartOption][IterationCount].accel_3:=0;
+ analysis_results[StartOption][IterationCount].accel_4:=0;
+ analysis_results[StartOption][IterationCount].accel_5:=0;
+ analysis_results[StartOption][IterationCount].accel_6:=0;
+ end;
+
+ maxpass:=3;
+ particle1_spin:=1;
+ particle2_spin:=1;
+ orthogonal_particles:=false;
+ particles_end_to_end:=false;
+ sine_wave_sum:=false;
+ E_Energy_Sum:=0;
+ B_Energy_Sum:=0;
+
+ proton:=false;
+ neutron:=false;
+ neutrino:=false;
+ neutrino_quarklets:=false;
+ quark_up:=false;
+ quark_down:=false;
+ r_lower_limit:=ElectronComptonRadius;
+
+ case StartOption of
+ 1: begin // if electron being modeled
+ electron:=true;
+ positron:=false;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 2: begin // if positron being modeled
+ electron:=false;
+ positron:=true;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 3: begin // if two electrons being modeled
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ end;
+
+ 4: begin // if two positrons being modeled
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ end;
+
+ 5: begin // if an electron and a positron being modeled
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ end;
+
+ 6: begin // if two electrons being modeled orthogonally
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ end;
+
+ 7: begin // if two positrons being modeled orthogonally
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ end;
+
+ 8: begin // if an electron and a positron being modeled orthogonally
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ end;
+
+ 9: begin // if two electrons being modeled orthogonally - reversed 2nd axis
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ particle2_spin:=-1;
+ end;
+
+ 10: begin // if two positrons being modeled orthogonally - reversed 2nd axis
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ particle2_spin:=-1;
+ end;
+
+ 11: begin // if an electron and a positron being modeled orthogonally - reversed 2nd axis
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ orthogonal_particles:=true;
+ particle2_spin:=-1;
+ end;
+
+ 12: begin // if two electrons being modeled spins end to end
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ end;
+
+ 13: begin // if two positrons being modeled spins end to end
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ end;
+
+ 14: begin // if an electron and a positron being modeled spins end to end
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ end;
+
+ 15: begin // if two electrons being modeled spins end to end - reversed 2nd axis
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ particle2_spin:=-1;
+ end;
+
+ 16: begin // if two positrons being modeled spins end to end - reversed 2nd axis
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ particle2_spin:=-1;
+ end;
+
+ 17: begin // if an electron and a positron being modeled spins end to end - reversed 2nd axis
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ particles_end_to_end:=true;
+ particle2_spin:=-1;
+ end;
+
+ 18: begin // if two electrons being modeled spins end to end - reversed 2nd spin axis
+ electron:=true;
+ positron:=false;
+ two_particles:=true;
+ end;
+
+ 19: begin // if two positrons being modeled spins end to end - reversed 2nd spin axis
+ electron:=false;
+ positron:=true;
+ two_particles:=true;
+ end;
+
+ 20: begin // if an electron and a positron being modeled spins end to end - reversed 2nd spin axis
+ electron:=true;
+ positron:=true;
+ two_particles:=true;
+ end;
+
+ 21: begin // if electron OUT wave being modeled
+ electron:=true;
+ positron:=false;
+ two_particles:=false;
+ sine_wave_sum:=true;
+ maxpass:=1;
+ end;
+
+ 22: begin // if electron IN wave being modeled
+ electron:=true;
+ positron:=false;
+ two_particles:=false;
+ sine_wave_sum:=true;
+ maxpass:=1;
+ end;
+
+ 23: begin // if electron OUT+IN wave being modeled
+ electron:=true;
+ positron:=false;
+ two_particles:=false;
+ sine_wave_sum:=true;
+ maxpass:=1;
+ end;
+
+ 24: begin // if proton being modeled
+ electron:=false;
+ positron:=false;
+ proton:=true;
+ r_lower_limit:=ProtonComptonRadius;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 25: begin // if neutron being modeled
+ electron:=false;
+ positron:=false;
+ neutron:=true;
+ r_lower_limit:=NeutronComptonRadius;
+ sine_wave_sum:=true;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 26: begin // if neutrino being modeled
+ electron:=false;
+ positron:=false;
+ neutrino:=true;
+ r_lower_limit:=ElectronNeutrinoComptonRadius;
+ neutrino_quarklets:=true;
+ sine_wave_sum:=neutrino_quarklets;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 27: begin // if Up Quark being modeled
+ electron:=false;
+ positron:=false;
+ proton:=false;
+ quark_up:=true;
+ r_lower_limit:=ProtonComptonRadius;
+ sine_wave_sum:=true;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+
+ 28: begin // if Down Quark being modeled
+ electron:=false;
+ positron:=false;
+ proton:=false;
+ quark_down:=true;
+ r_lower_limit:=ProtonComptonRadius;
+ sine_wave_sum:=true;
+ two_particles:=false;
+ maxpass:=1;
+ end;
+ end;
+
+ if StartOptionChanged then begin
+ if (electron or positron or proton or neutron or neutrino) then begin
+ if not EFormulaCheckBox.Enabled then begin
+ EFormulaCheckBox.Checked:=true;
+ HFormulaCheckBox.Checked:=true;
+ EFormulaCheckBox.Enabled:=true;
+ HFormulaCheckBox.Enabled:=true;
+ end;
+ end
+ else begin
+ EFormulaCheckBox.Checked:=false;
+ HFormulaCheckBox.Checked:=false;
+ EFormulaCheckBox.Enabled:=false;
+ HFormulaCheckBox.Enabled:=false;
+ end;
+
+ if (proton or neutron or quark_up or quark_down) then begin
+ // Note: at 270x270x270 GridSize, an actual width of 4E-14 (11 grid points per Compton wavelength) gives a very accurate energy calculation
+ ActualGridWidth.Text:=FloatToStrf(1.5E-14,ffExponent,5,2); {display actual size in metres that grid represents}
+ RateOfTime.Position:=3;
+ ProcSetGridGlobals(Self);
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else if neutrino then begin
+ // Note: at 270x270x270 a GridWidth of 142 Compton wavelengths gives a very accurate energy calculation
+ if neutrino_quarklets then
+ ActualGridWidth.Text:=FloatToStrf(2.0E-6,ffExponent,5,2) {display actual size in metres that grid represents}
+ else
+ ActualGridWidth.Text:=FloatToStrf(2.7E-5,ffExponent,5,2); {display actual size in metres that grid represents}
+ RateOfTime.Position:=4000;
+ New_RateOfTime:=RateOfTime.Position * 40000;
+ ProcSetGridGlobals(Self);
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ // Note: at 270x270x270 GridSize, an actual width of 7.6E-11 (11 grid points per Compton wavelength) gives a very accurate energy calculation
+ ActualGridWidth.Text:=FloatToStrf(3.0E-11,ffExponent,5,2); {display actual size in metres that grid represents}
+ RateOfTime.Position:=4000;
+ ProcSetGridGlobals(Self);
+ DoUpdate:=true;
+ Restart:=true;
+ end;
+ end;
+
+ if maxpass=1 then progress_inc:=22;
+
+ if two_particles then begin
+ Percent_c.Visible:=false;
+ DistBetweenLabel.Visible:=true;
+ DistBetween.Visible:=true;
+ DistBetweenUnits.Visible:=true;
+ ShowEnergy_CheckBox.Visible:=true;
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ Field11.Visible:=true;
+ Field12.Visible:=true;
+{$IFEND}
+ if (Time = 0) then begin
+ try
+ PercentBetweenParticles:=strtofloat(DistBetween.Text);
+ if (0 = PercentBetweenParticles) then begin
+ DistBetween.Text:='50';
+ PercentBetweenParticles:=strtofloat(DistBetween.Text);
+ end;
+ PercentBetweenParticles:=Round(PercentBetweenParticles*100)/100;
+ except
+ on E: Exception do begin
+ PercentBetweenParticles:=30;
+ DistBetween.Text:='30';
+ end;
+ end;
+ DistFromCenter:=((PercentBetweenParticles/2)/100)*GridWidth;
+
+ particle1_x:=GridWidth/2 - DistFromCenter;
+ particle2_x:=GridWidth/2 + DistFromCenter;
+ p1_p2_diff:=abs(particle2_x - particle1_x);
+ end
+ else begin
+ p1_p2_diff:=abs(particle2_x - particle1_x);
+ DistFromCenter:=p1_p2_diff/2;
+ PercentBetweenParticles:=100*p1_p2_diff/GridWidth;
+ PercentBetweenParticles:=Round(PercentBetweenParticles*100)/100;
+ DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+ end;
+ end
+ else begin
+ Percent_c.Visible:=true;
+ DistBetweenLabel.Visible:=false;
+// DistBetween.Visible:=false;
+// DistBetweenUnits.Visible:=false;
+ ShowEnergy_CheckBox.Visible:=false;
+ Field11.Visible:=false;
+ Field12.Visible:=false;
+ end;
+
+ NewScreen:=0;
+// if scr=0 then NewScreen:=1 else NewScreen:=0; {determine which data to update}
+
+ for pass := 1 to maxpass do begin
+ if two_particles then begin
+ if (pass = 1) then begin
+ saved_sign:=particle2_spin;
+ particle2_spin:=0;
+ end
+ else if (pass = 2) then begin
+ particle2_spin:=saved_sign;
+ saved_sign:=particle1_spin;
+ particle1_spin:=0;
+ end
+ else begin
+ particle1_spin:=saved_sign;
+ end;
+ end;
+
+ if field_stats and (pass=1) then begin
+ PsiSum:=0;
+ PsiSumXpos:=0;
+ PsiSumYpos:=0;
+ PsiSumZpos:=0;
+ PsiSumXneg:=0;
+ PsiSumYneg:=0;
+ PsiSumZneg:=0;
+ ElectricPotentialSum_pos:=0;
+ ElectricPotentialSum_neg:=0;
+ ElectricPotentialSum:=0;
+ ElecFieldCurl_Sum:=0;
+ ElecFieldFromV_Sum:=0;
+ ElecFieldFromV_SignedHalf_SumX:=0;
+ ElecFieldFromA_SignedHalf_SumX:=0;
+ ElecFieldGradDivPsi_SignedHalf_SumX:=0;
+ ElecFieldCurlCurlPsi_SignedHalf_SumX:=0;
+ ElecFieldFromA_Sum:=0;
+ ElecField_Sum:=0;
+ MagField_Sum:=0;
+ VectorPotential_Sum:=0;
+ end;
+
+ if not Flip_YZ then begin
+
+ midx:=Trunc(GridWidth/2);
+ midy:=Trunc(GridHeight/2);
+ midz:=Trunc(GridDepth/2);
+
+ /////////////////////////////////////
+
+ if neutrino then begin
+ SpinConstant:=( Hhat / ElectronNeutrinoMass ); // Metres^2/(Radians*Second)
+ delta := ( UnitaryCharge * Hhat ) / ( 2 * Pi * ElectronNeutrinoMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=sign(ElectronCharge)*( ElectronNeutrinoMass * sqr(SpeedOfLight) ) / Hhat;
+ end
+ else if proton then begin
+ SpinConstant:=( Hhat / ProtonMass ); // Metres^2/(Radians*Second)
+ delta := ( ProtonCharge * Hhat ) / ( 2 * Pi * ProtonMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=sign(ProtonCharge)*( ProtonMass * sqr(SpeedOfLight) ) / Hhat;
+ end
+ else if neutron then begin
+ SpinConstant:=( Hhat / NeutronMass ); // Metres^2/(Radians*Second)
+ delta := ( UnitaryCharge * Hhat ) / ( 2 * Pi * NeutronMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=( NeutronMass * sqr(SpeedOfLight) ) / Hhat;
+ end
+ else if quark_up then begin
+ SpinConstant:=( Hhat / ProtonMass ); // Metres^2/(Radians*Second)
+ delta := ( (2/3)*ProtonCharge * Hhat ) / ( 2 * Pi * ProtonMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=sign(ProtonCharge)*( ProtonMass * sqr(SpeedOfLight) ) / Hhat;
+ end
+ else if quark_down then begin
+ SpinConstant:=( Hhat / ProtonMass ); // Metres^2/(Radians*Second)
+ delta := ( (1/3)*ProtonCharge * Hhat ) / ( 2 * Pi * ProtonMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=sign(ProtonCharge)*( ProtonMass * sqr(SpeedOfLight) ) / Hhat;
+ end
+ else begin // electrons and/or positrons
+ SpinConstant:=( Hhat / ElectronMass ); // Metres^2/(Radians*Second)
+ delta := ( ElectronCharge * Hhat ) / ( 2 * Pi * ElectronMass * SpeedOfLight * Permittivity );
+
+ // theta_const is in Radians/Second ( i.e. the same as solving E = hf for f, where E=mc^2, and h=2*Pi*Hhat,
+ // then converting f to angular frequency w, via w = 2*Pi*f )
+ // ( theta_const could be, equivalently : - c^2/SpinConstant )
+ theta_const:=( -ElectronMass * sqr(SpeedOfLight) ) / Hhat;
+ end;
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ if (pass = 1) then begin
+ if (Time = 0) then begin
+ if two_particles then Velocity:=0
+ else particle1_x:=midx;
+ end;
+
+ if (two_particles and not ShowEnergy_CheckBox.Checked) then begin
+ Edit1.Text:='Calculated Acceleration';
+ Edit2.Text:=' m/s^2';
+
+// Energy_Msg3.Text:='Reflected Energy Components';
+ Energy_Msg3.Text:='Expected Acceleration';
+ Units3.text:=' m/s^2';
+ end
+ else begin
+ Energy_Msg3.Text:='Total Energy';
+ Units3.text:=' Joules';
+ Edit2.Text:=' Joules';
+
+{
+ if (Time = 0) then begin
+
+ Edit1.Text:='Total Energy (Integrated) ';
+ Edit2.Text:=' Joules';
+
+ Energy_Msg3.Text:='Total Energy';
+
+ Etotal:=0;
+ ShellThickness:=5E-15;
+
+ for dist := 1 to 1000000000 do begin
+ r:=dist*ShellThickness;
+
+ term1:=ElectronCharge/(4*Pi*sqr(r)*Permittivity);
+
+ // Twice the Electric Field energy (the Energy in the Magnetic field is equal to that in the Electric field
+ // for a wave that satisfies the Classical Wave Equation).
+ Etotal:=Etotal + 2*ShellThickness*(4*Pi*sqr(r)) * 0.5*Permittivity*sqr(term1);
+ end;
+ end;
+}
+ end;
+ end;
+
+ if neutrino then
+ Etotal:=ElectronNeutrinoMass*sqr(SpeedOfLight)
+ else if proton then
+ Etotal:=(Permeability*sqr(SpeedOfLight) + 1/Permittivity)*sqr(ProtonCharge)/(8*Pi*ProtonClassicalRadius)
+ else if neutron then
+ Etotal:=NeutronMass*sqr(SpeedOfLight)
+ else if quark_up then
+ Etotal:=UpQuarkMass*sqr(SpeedOfLight)
+ else if quark_down then
+ Etotal:=DownQuarkMass*sqr(SpeedOfLight)
+ else
+ Etotal:=(Permeability*sqr(SpeedOfLight) + 1/Permittivity)*sqr(ElectronCharge)/(8*Pi*ElectronClassicalRadius);
+
+ if two_particles then Etotal := 2*Etotal;
+
+ if not two_particles or ShowEnergy_CheckBox.Checked then begin
+ // According to QM
+ // See: https://paradox-paradigm.nl/preface/the-equivalence-of-magnetic-and-kinetic-energy/the-moving-electron-and-magnetic-energy/
+ Edit1.Text:='Actual Rest Energy ';
+ Energy4.Text:=FloatToStr(Etotal); {display total H field energy}
+ end;
+
+ //
+ // Thus Total Electron Wave Equation (Ye) is:
+ //
+ // Ye = ((Qe*Hhat) / (2*Pi*r*i*Me*c*Eo )) * Exp( ( - i * Me * c^2 / Hhat ) * ( T – r/c ) )
+ //
+ // and the Electric Potential div(psi) in spherical coordinates is
+ //
+ // V = (Qe / ( 2 * Pi * r * Me * c * Eo )) * (Me * c * r – i * Hhat) * Exp( ( - i * Me * c^2 / Hhat ) * ( T – r/c ) )
+ //
+ // Where:
+ // Ye is Electron Wave Function (psi)
+ // Qe is Electron's Charge
+ // Pi is 3.14159 etc
+ // Eo is the Permittivity of free space
+ // Exp is the Exponential function
+ // i is the Complex number (square root of -1)
+ // Me is the Mass of an Electron
+ // c is the speed of light
+ // Hhat is the reduced Plancks constant ( i.e. h/(2*Pi) )
+ // T is Time
+ // r is the radial distance from the center of the Electron
+ //
+ // exp(-theta) = cos(theta) - isin(theta)
+ // using x,y,z coordinates:
+ // x = cos(theta)
+ // y = sin(theta)
+
+ // theta:=theta_const*(Time - k*r*r/2);
+ //
+ // term1:=delta/r
+ //
+ // term2:=cos(theta);
+ // term3:=-sin(theta);
+ //
+ // if ( ViewTop ) then begin // Assign values to x, y, z coordinates, depending on view from the top or side.
+ // x:=term1 * term2;
+ // y:=term1 * term3;
+ // z:=0;
+ // end
+ // else begin
+ // x:=term1 * term2;
+ // y:=0;
+ // z:=term1 * term3;
+ // end;
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ /////////////////////////////////////
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+ ThisGroup:=PointGroup(scr, xpos, ypos, zpos);
+
+ x:= xpos - midx;
+ y:= ypos - midy;
+ z:= zpos - midz;
+
+ if two_particles then begin
+ // get actual distance in metres
+ r1:=sqrt( sqr((xpos - particle1_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r1 < r_lower_limit ) then r1:=r_lower_limit; // prevent divide by zero errors
+
+ // get actual distance in metres
+ r2:=sqrt( sqr((xpos - particle2_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r2 < r_lower_limit ) then r2:=r_lower_limit; // prevent divide by zero errors
+
+ r_gamma:=1;
+ end
+ else begin
+ r:=sqrt( sqr(x*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r < r_lower_limit ) then r:=r_lower_limit; // prevent divide by zero errors
+
+ velocity := SpeedOfLight*(strtofloat(DistBetween.Text)/100);
+ gamma := 1/(sqrt(1 - sqr(velocity)/sqr(SpeedOfLight)));
+
+ x_contracted := (x*dx)/gamma;
+
+ r_contracted:=sqrt( sqr(x_contracted) + sqr(y*dy) + sqr(z*dz) );
+ if ( r_contracted < r_lower_limit ) then r_contracted:=r_lower_limit; // prevent divide by zero errors
+
+ r_gamma:=sqrt( sqr((x*dx)*gamma) + sqr(y*dy) + sqr(z*dz) );
+ if ( r_gamma < r_lower_limit ) then r_gamma:=r_lower_limit; // prevent divide by zero errors
+
+ x_sign := 1;
+ if (xpos < midx) then x_sign := -x_sign;
+ x_velocity := sqrt(sqr(x*dx)/sqr(r))*x_sign*velocity;
+ end;
+
+ /////////////////////////////////////
+ /// WAVE FUNCTION TO TEST
+ ///
+ ///
+ term1:=delta/r_gamma;
+
+ case StartOption of
+ 1: begin // if electron being modeled
+ theta:=theta_const*(Time - r/(SpeedOfLight + x_velocity));
+ end;
+
+ 2: begin // if positron being modeled
+ theta:=theta_const*(Time + r/(SpeedOfLight + x_velocity));
+ end;
+
+ 3: begin // if two electrons being modeled
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 4: begin // if two positrons being modeled
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 5: begin // if an electron and a positron being modeled
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 6: begin // if two electrons being modeled orthogonally
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 7: begin // if two positrons being modeled orthogonally
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=sign(PositronCharge) * abs(delta)/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 8: begin // if an electron and a positron being modeled orthogonally
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 9: begin // if two electrons being modeled orthogonally - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 10: begin // if two positrons being modeled orthogonally - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=sign(PositronCharge) * abs(delta)/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 11: begin // if an electron and a positron being modeled orthogonally - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 12: begin // if two electrons being modeled spins end to end
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 13: begin // if two positrons being modeled spins end to end
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=sign(PositronCharge) * abs(delta)/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 14: begin // if an electron and a positron being modeled spins end to end
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 15: begin // if two electrons being modeled spins end to end - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 16: begin // if two positrons being modeled spins end to end - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=sign(PositronCharge) * abs(delta)/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 17: begin // if an electron and a positron being modeled spins end to end - reversed 2nd axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 18: begin // if two electrons being modeled spins opposite - reversed 2nd spin axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time - r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=delta/r2;
+ end;
+
+ 19: begin // if two positrons being modeled spins opposite - reversed 2nd spin axis
+ theta1:=particle1_spin*theta_const*(Time + r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=sign(PositronCharge) * abs(delta)/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 20: begin // if an electron and a positron being modeled spins opposite - reversed 2nd spin axis
+ theta1:=particle1_spin*theta_const*(Time - r1/SpeedOfLight);
+ theta2:=particle2_spin*theta_const*(Time + r2/SpeedOfLight);
+ term1a:=delta/r1;
+ term1b:=sign(PositronCharge) * abs(delta)/r2;
+ end;
+
+ 21: begin // if electron OUT wave being modeled
+ // X coordinate terms
+ term2:=0;
+
+ // each IN/OUT wave component is only half the wave-function amplitude
+ if not CheckBox4.Checked then term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight - x_velocity))); // IN y2
+ //if not CheckBox5.Checked then term2:=term2 + 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y1
+ //if not CheckBox6.Checked then term2:=term2 - 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y5
+ if not CheckBox7.Checked then term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y6
+
+ // Y coordinate terms
+ term3:=0;
+ if not CheckBox8.Checked then term3:=term3 - 0.5*Sin(theta_const*(Time + r/(SpeedOfLight + x_velocity))); // OUT y7
+ if not CheckBox9.Checked then term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y3
+ if not CheckBox10.Checked then term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y8
+ if not CheckBox11.Checked then term3:=term3 + 0.5*Sin(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y4
+
+ if FrameCount > 30 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 22: begin // if electron IN wave being modeled
+ // X coordinate terms
+ term2:=0;
+
+ // each IN/OUT wave component is only half the wave-function amplitude
+ if CheckBox4.Checked then term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight - x_velocity))); // IN y2
+ //if CheckBox5.Checked then term2:=term2 + 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y1
+ //if CheckBox6.Checked then term2:=term2 - 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y5
+ if CheckBox7.Checked then term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y6
+
+ // Y coordinate terms
+ term3:=0;
+ if CheckBox8.Checked then term3:=term3 - 0.5*Sin(theta_const*(Time + r/(SpeedOfLight + x_velocity))); // OUT y7
+ if CheckBox9.Checked then term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y3
+ if CheckBox10.Checked then term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y8
+ if CheckBox11.Checked then term3:=term3 + 0.5*Sin(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y4
+
+ if FrameCount > 30 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 23: begin // if electron OUT+IN wave being modeled
+ // X coordinate terms
+ term2:=0;
+
+ // each IN/OUT wave component is only half the wave-function amplitude
+ term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight - x_velocity))); // IN y2
+ //term2:=term2 + 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y1
+ //term2:=term2 - 0.5*Cos(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y5
+ term2:=term2 + 0.5*Cos(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y6
+
+ // Y coordinate terms
+ term3:=0;
+ term3:=term3 - 0.5*Sin(theta_const*(Time + r/(SpeedOfLight + x_velocity))); // OUT y7
+ term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y3
+ term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y8
+ term3:=term3 + 0.5*Sin(theta_const*(Time + r/(SpeedOfLight - x_velocity))); // IN y4
+
+ if FrameCount > 30 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 24: begin // if proton being modeled
+ theta:=theta_const*(Time + r/(SpeedOfLight + x_velocity));
+
+ if FrameCount > 44 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 25: begin // if neutron being modeled
+ // IN component of Proton wave-function = 2 UP Quarks (IN)
+ // OUT component of Proton wave-function = 1 DOWN Quark (OUT)
+ //
+ // In Neutron wave-function we have 1 UP & 2 DOWN Quarks, so:
+ // Neutron wave components: IN = IN(Proton)/2 + OUT(Proton)*2
+
+ // X coordinate terms
+ term2:=0;
+
+ // each IN/OUT wave component is only half the wave-function amplitude
+ term2:=term2 + 2.0 * 0.5*Cos(theta_const*(-Time - r/(SpeedOfLight + x_velocity))); // OUT y2
+ //term2:=term2 + 2.0 * 0.5*Cos(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y1
+ //term2:=term2 - 2.0 * 0.5*Cos(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y5
+ term2:=term2 + 0.5 * 0.5*Cos(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y6
+
+ // Y coordinate terms
+ term3:=0;
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(Time - r/(SpeedOfLight - x_velocity))); // IN y7
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y3
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y8
+ term3:=term3 + 2.0 * 0.5*Sin(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y4
+
+ if FrameCount > 44 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 26: begin // if electron neutrino being modeled
+ if neutrino_quarklets then begin
+ // IN component of Proton wave-function = 2 UP Quarks (IN)
+ // OUT component of Proton wave-function = 1 DOWN Quark (OUT)
+ //
+ // In Neutrino wave-function we have 1 UP & 2 DOWN Quarklets, so:
+ // Neutrino wave components: IN = IN(Proton)/2 + OUT(Proton)*2
+
+ // X coordinate terms
+ term2:=0;
+
+ // each IN/OUT wave component is only half the wave-function amplitude
+ term2:=term2 + 2.0 * 0.5*Cos(theta_const*(-Time - r/(SpeedOfLight + x_velocity))); // OUT y2
+ //term2:=term2 + 2.0 * 0.5*Cos(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y1
+ //term2:=term2 - 2.0 * 0.5*Cos(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y5
+ term2:=term2 + 0.5 * 0.5*Cos(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y6
+
+ // Y coordinate terms
+ term3:=0;
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(Time - r/(SpeedOfLight - x_velocity))); // IN y7
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y3
+ term3:=term3 - 0.5 * 0.5*Sin(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y8
+ term3:=term3 + 2.0 * 0.5*Sin(theta_const*(Time - r/(SpeedOfLight + x_velocity))); // OUT y4
+ end
+ else begin
+ theta:=theta_const*Time;
+ end;
+
+ if FrameCount > 236 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 27: begin // if Up Quark being modeled
+ // X coordinate terms
+ term2:=0;
+ term2:=term2 + 0.25*Cos(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y6/2
+
+ // Y coordinate terms
+ term3:=0;
+ term3:=term3 - 0.5*Sin(theta_const*(-Time - r/(SpeedOfLight - x_velocity))); // IN y3
+ term3:=term3 + 0.25*Sin(theta_const*(-Time + r/(SpeedOfLight - x_velocity))); // IN y7/2
+
+ if FrameCount > 44 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+
+ 28: begin // if Down Quark being modeled
+ // X coordinate terms
+ term2:=0;
+ term2:=term2 + 0.5*Cos(theta_const*(-Time - r/(SpeedOfLight + x_velocity))); // OUT y2
+
+ // Y coordinate terms
+ term3:=0;
+ term3:=term3 - 0.5*Sin(theta_const*(-Time + r/(SpeedOfLight + x_velocity))); // OUT y4
+
+ if FrameCount > 44 then begin
+ CheckBox1.Checked:=false;
+ save_frames:=false;
+ end;
+ end;
+ end;
+
+ if not sine_wave_sum then begin
+ if two_particles then begin
+ SinCos(theta1, term3a, term2a);
+ SinCos(theta2, term3b, term2b);
+
+ // Note: the absolute value of the particle spin is used as the spin can take values of -1, 0 +1.
+ // When it is 0 that particle is excluded from the calculation.
+ term1a := abs(particle1_spin)*term1a;
+ term1b := abs(particle2_spin)*term1b;
+
+ psi_x_particle1 := term1a * term2a;
+ psi_y_particle1 := term1a * term3a;
+ psi_z_particle1 := 0;
+
+ psi_x_particle2 := term1b * term2b;
+ psi_y_particle2 := term1b * term3b;
+ psi_z_particle2 := 0;
+ end
+ else begin
+ SinCos(theta, term3, term2);
+ end;
+ end;
+
+ if not two_particles then begin
+ psi_x := term1 * term2;
+ psi_y := term1 * term3;
+ psi_z := 0;
+ end;
+
+ // Assign values to x, y, z coordinates, depending on view from the top or side.
+ with points[NewScreen]^[xpos,ypos,zpos].PsiVect do begin
+ if two_particles then begin
+ if ( ViewTop ) then begin
+ if orthogonal_particles then begin
+ // x1' = x1
+ // y1' = y1
+ // z1' = z1
+ // x2' = z2
+ // y2' = y2
+ // z2' = -x2
+ x:=psi_x_particle1 + psi_z_particle2;
+ y:=psi_y_particle1 + psi_y_particle2;
+ z:=psi_z_particle1 - psi_x_particle2;
+ end
+ else if particles_end_to_end then begin
+ // x1' = z1
+ // y1' = y1
+ // z1' = -x1
+ // x2' = z2
+ // y2' = y2
+ // z2' = -x2
+ x:=psi_z_particle1 + psi_z_particle2;
+ y:=psi_y_particle1 + psi_y_particle2;
+ z:=-psi_x_particle1 - psi_x_particle2;
+ end
+ else begin
+ x:=psi_x_particle1 + psi_x_particle2;
+ y:=psi_y_particle1 + psi_y_particle2;
+ z:=psi_z_particle1 + psi_z_particle2;
+ end;
+ end
+ // If not 'view from top', then 'view from side' & screen axes are x & z, so z axis takes y component & y takes the z axis.
+ else begin
+ if orthogonal_particles then begin
+ // x1' = x1
+ // y1' = y1 -> z1
+ // z1' = z1 -> y1
+ // x2' = y2 -> z2
+ // y2' = -x2
+ // z2' = z2 -> y2
+ x:=psi_x_particle1 + psi_z_particle2; // x1' + x2'
+ y:=psi_z_particle1 - psi_x_particle2; // y1' + y2'
+ z:=psi_y_particle1 + psi_y_particle2; // z1' + z2'
+ end
+ else if particles_end_to_end then begin
+ // x1' = y1 -> z1
+ // y1' = -x1
+ // z1' = z1 -> y1
+ // x2' = y2 -> z2
+ // y2' = -x2
+ // z2' = z2 -> y2
+ x:=psi_z_particle1 + psi_z_particle2; // x1' + x2'
+ y:=-psi_x_particle1 - psi_x_particle2; // y1' + y2'
+ z:=psi_y_particle1 + psi_y_particle2; // z1' + z2'
+ end
+ else begin
+ x:=psi_x_particle1 + psi_x_particle2;
+ y:=psi_z_particle1 + psi_z_particle2;
+ z:=psi_y_particle1 + psi_y_particle2;
+ end;
+ end;
+ points[NewScreen]^[xpos,ypos,zpos].Psi := term1a + term1b;
+ end
+ else begin
+ if ( ViewTop ) then begin
+ x:=psi_x;
+ y:=psi_y;
+ z:=psi_z;
+ end
+ else begin
+ x:=psi_x;
+ y:=psi_z;
+ z:=psi_y;
+ end;
+ points[NewScreen]^[xpos,ypos,zpos].Psi := term1;
+ end;
+ end;
+
+ if field_stats and (pass=1) then begin
+ PsiSum:=PsiSum + VectSize(points[NewScreen]^[xpos,ypos,zpos].PsiVect);
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.x > 0) then PsiSumXpos:=PsiSumXpos + points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.y > 0) then PsiSumYpos:=PsiSumYpos + points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.z > 0) then PsiSumZpos:=PsiSumZpos + points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.x < 0) then PsiSumXneg:=PsiSumXneg + points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.y < 0) then PsiSumYneg:=PsiSumYneg + points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ if (points[NewScreen]^[xpos,ypos,zpos].PsiVect.z < 0) then PsiSumZneg:=PsiSumZneg + points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end;
+
+ ///
+ ///
+ /////////////////////////////////////
+
+ end;
+ end;
+ end; // end {scan grid's x coords}
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+
+ ThisGroup:=PointGroup(scr, xpos, ypos, zpos);
+ NewGroup:=PointGroup(NewScreen, xpos, ypos, zpos);
+
+ with points[NewScreen]^[xpos,ypos,zpos] do begin
+ if (smoothing) then begin
+ x:= xpos - midx;
+ y:= ypos - midy;
+ z:= zpos - midz;
+
+ if two_particles then begin
+ // get actual distance in metres
+ r1:=sqrt( sqr((xpos - particle1_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r1 < r_lower_limit ) then r1:=r_lower_limit; // prevent divide by zero errors
+
+ // get actual distance in metres
+ r2:=sqrt( sqr((xpos - particle2_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r2 < r_lower_limit ) then r2:=r_lower_limit; // prevent divide by zero errors
+
+ ElectricPotential:=0;
+
+ if (pass=1) or (pass=3) then begin
+ if electron then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*ElectronCharge/(4*Pi*r1*Permittivity)
+ else if positron then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*PositronCharge/(4*Pi*r1*Permittivity)
+ else if proton then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*ProtonCharge/(4*Pi*r1*Permittivity)
+ else if neutron then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*NeutronCharge/(4*Pi*r1*Permittivity)
+ else if quark_up then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*(2/3)*ProtonCharge/(4*Pi*r1*Permittivity)
+ else if quark_down then
+ ElectricPotential:=ElectricPotential + abs(particle1_spin)*(1/3)*ProtonCharge/(4*Pi*r1*Permittivity);
+ end;
+
+ if (pass=2) or (pass=3) then begin
+ if positron then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*PositronCharge/(4*Pi*r2*Permittivity)
+ else if electron then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*ElectronCharge/(4*Pi*r2*Permittivity)
+ else if proton then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*ProtonCharge/(4*Pi*r1*Permittivity)
+ else if neutron then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*NeutronCharge/(4*Pi*r1*Permittivity)
+ else if quark_up then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*(2/3)*ProtonCharge/(4*Pi*r1*Permittivity)
+ else if quark_down then
+ ElectricPotential:=ElectricPotential + abs(particle2_spin)*(1/3)*ProtonCharge/(4*Pi*r1*Permittivity);
+ end;
+ end
+ else begin
+ // get actual distance in metres
+ r:=sqrt( sqr(x*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r < r_lower_limit ) then r:=r_lower_limit; // prevent divide by zero errors
+
+ if electron then
+ ElectricPotential:=ElectronCharge/(4*Pi*r*Permittivity)
+ else if positron then
+ ElectricPotential:=PositronCharge/(4*Pi*r*Permittivity)
+ else if proton then
+ ElectricPotential:=ProtonCharge/(4*Pi*r*Permittivity)
+ else if neutron then
+ ElectricPotential:=NeutronCharge/(4*Pi*r*Permittivity)
+ else if quark_up then
+ ElectricPotential:=(2/3)*ProtonCharge/(4*Pi*r*Permittivity)
+ else if quark_down then
+ ElectricPotential:=(1/3)*ProtonCharge/(4*Pi*r*Permittivity);
+ end;
+ end
+ else begin
+ // Curl of Psi Vector Field
+ VectGrp:=VectorGroup(NewGroup, PSI_VECTOR_FIELD);
+ PsiCurlVect:=VectCurl(VectGrp);
+ // Div of Psi Vector Field
+ ElectricPotential:=VectDiv(VectGrp);
+ end;
+
+ if field_stats and (pass=1) then begin
+ if (ElectricPotential > 0) then ElectricPotentialSum_pos:=ElectricPotentialSum_pos + ElectricPotential;
+ if (ElectricPotential < 0) then ElectricPotentialSum_neg:=ElectricPotentialSum_neg + ElectricPotential;
+ end;
+ end;
+ end;
+ end;
+ end; // end {scan grid's x coords}
+
+ if field_stats then ElectricPotentialSum:=ElectricPotentialSum_pos + ElectricPotentialSum_neg;
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+
+ ThisGroup:=PointGroup(scr, xpos, ypos, zpos);
+ NewGroup:=PointGroup(NewScreen, xpos, ypos, zpos);
+
+ { ThisGroup's points are assigned as follows: P3 P5
+ P1 P0 P2
+ P4 P6
+ Where P5 & P6 are in the Z plane (P5 at the back and P6 at the front) }
+
+ x:= xpos - midx;
+ y:= ypos - midy;
+ z:= zpos - midz;
+
+ if (not smoothing) then begin
+ // Curl of Psi Vector Potential Field
+ VectGrp:=VectorGroup(NewGroup, PSI_CURL_VECTOR_FIELD);
+ CurlVect:=VectCurl(VectGrp);
+ if field_stats and (pass=1) then ElecFieldCurl_Sum:= ElecFieldCurl_Sum + VectSize(CurlVect);
+ end;
+
+ // Electric Field is: Grad(Div(Psi)) - d/dt of Vector Potential field
+ Scalar_Group:=ScalarGroup(NewGroup, ELECTRIC_POTENTIAL_FIELD);
+
+ // This is the Vector Laplacian of Psi, which is -grad of ElectricPotential minus dA/dt.
+ // As Cartesian coordinates are being used, the Vector Laplacian is calculated as the
+ // Scalar Laplacian on each x,y,z coordinate.
+ // (will add the rest of the Electric field definition once the Vector Potential is known)
+ // E = -grad(div(Psi)) - dA/dt
+ vect:=ScalarGrad(Scalar_Group);
+
+ // This is -grad(div(Psi))
+ with ElecFieldFromV do begin
+ x:= -vect.x;
+ y:= -vect.y;
+ z:= -vect.z;
+ end;
+
+ if field_stats and (pass=1) then begin
+ ElecFieldFromV_Sum:= ElecFieldFromV_Sum + VectSize(ElecFieldFromV);
+
+ if (xpos <= particle1_x) then begin
+ ElecFieldFromV_SignedHalf_SumX:= ElecFieldFromV_SignedHalf_SumX + ElecFieldFromV.x;
+ ElecFieldGradDivPsi_SignedHalf_SumX:= ElecFieldGradDivPsi_SignedHalf_SumX + vect.x;
+ ElecFieldCurlCurlPsi_SignedHalf_SumX:= ElecFieldCurlCurlPsi_SignedHalf_SumX + CurlVect.x;
+ end;
+ end;
+
+ // From Schrodinger's wave equation:
+ // d(psi)/dt = i * Hhat/ElectronMass * Laplacian(psi)
+ //
+ // Note: div(V) = Laplacian(psi)
+ // SpinConstant = Hhat/ElectronMass
+ //
+ // So…
+ // d(psi)/dt = i*SpinConstant*div(V)
+ //
+ // VectorPotential = (1/c^2)*d(psi)/dt
+ //
+ // A is orthogonal to and proportional to the div(V) vector
+ // (multiplying by i rotates the vector 90 degrees in the complex plane).
+ // so use the Normal vector to the div(V) vector and the Static Electric field amplitude (E_amp).
+
+ with points[NewScreen]^[xpos,ypos,zpos].VectorPotential do begin
+ if (smoothing) then begin
+ // get amplitude of Static Electric field component
+ E_amp:=VectSize(ElecFieldFromV);
+ if ( E_amp < 0.00000000000001 ) then E_amp:=0.00000000000001; // prevent divide by zero errors
+
+ // Calculate the Unit & Normal vectors of the div(V) vector (depending on view from top or side)
+ with ElecFieldFromV do begin
+ unit_x:= x/E_amp;
+ unit_y:= y/E_amp;
+ unit_z:= z/E_amp;
+
+ if ( ViewTop ) then begin
+ normal_x:=unit_y;
+ normal_y:=-unit_x;
+ normal_z:=unit_z;
+ end
+ else begin
+ normal_x:=unit_z;
+ normal_y:=unit_y;
+ normal_z:=-unit_x;
+ end;
+ end;
+
+ x := normal_x*SpinConstant*E_amp/sqr(SpeedOfLight);
+ y := normal_y*SpinConstant*E_amp/sqr(SpeedOfLight);
+ z := normal_z*SpinConstant*E_amp/sqr(SpeedOfLight);
+ end
+ else begin
+ // Rotation Matrix, multiplying by i (viewed from the top):
+ //
+ // x' = -y
+ // y' = x
+ // z' = z
+ //
+ // But when viewed from the side z and y are swapped, so:
+ //
+ // x' = -z
+ // y' = y
+ // z' = x
+
+ // A = - (1/c^2)*dYe/dt = -i*(Me/Hhat)*Ye
+ if ( ViewTop ) then begin
+ if neutrino then begin
+ x := -(-(ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end
+ else if proton then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end
+ else if neutron then begin
+ x := -(-(NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end
+ else if quark_up then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end
+ else if quark_down then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end
+ else begin
+ x := -(-(ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ y := -((ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ z := -((ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ end;
+ end
+ else begin
+ if neutrino then begin
+ x := -(-(ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((ElectronNeutrinoMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end
+ else if proton then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end
+ else if neutron then begin
+ x := -(-(NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((NeutronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end
+ else if quark_up then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end
+ else if quark_down then begin
+ x := -(-(ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((ProtonMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end
+ else begin
+ x := -(-(ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z);
+ y := -((ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y);
+ z := -((ElectronMass/Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x);
+ end;
+ end;
+ end;
+ end;
+
+ if field_stats and (pass=1) then VectorPotential_Sum:= VectorPotential_Sum + VectSize(points[NewScreen]^[xpos,ypos,zpos].VectorPotential);
+
+// PrevVectorPotential:= points[scr]^[xpos,ypos,zpos].VectorPotential;
+
+ if two_particles then begin
+ if (pass=1) then begin
+ PrevVectorPotential:=particle1_A[xpos,ypos,zpos];
+ end
+ else if (pass=2) then begin
+ PrevVectorPotential:=particle2_A[xpos,ypos,zpos];
+ end;
+ end
+ else begin
+ PrevVectorPotential:=particle1_A[xpos,ypos,zpos];
+ end;
+
+ if (smoothing) then begin
+ ElecFieldFromA.x := (1/TimeStep)*(points[NewScreen]^[xpos,ypos,zpos].VectorPotential.x - PrevVectorPotential.x);
+ ElecFieldFromA.y := (1/TimeStep)*(points[NewScreen]^[xpos,ypos,zpos].VectorPotential.y - PrevVectorPotential.y);
+ ElecFieldFromA.z := (1/TimeStep)*(points[NewScreen]^[xpos,ypos,zpos].VectorPotential.z - PrevVectorPotential.z);
+ end
+ else begin
+ // dA/dt = -(Me*c/Hhat)^2*Ye
+ if neutrino then begin
+ ElecFieldFromA.x := -sqr(ElectronNeutrinoMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(ElectronNeutrinoMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(ElectronNeutrinoMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end
+ else if proton then begin
+ ElecFieldFromA.x := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end
+ else if neutron then begin
+ ElecFieldFromA.x := -sqr(NeutronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(NeutronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(NeutronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end
+ else if quark_up then begin
+ ElecFieldFromA.x := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end
+ else if quark_down then begin
+ ElecFieldFromA.x := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(ProtonMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end
+ else begin
+ ElecFieldFromA.x := -sqr(ElectronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.x;
+ ElecFieldFromA.y := -sqr(ElectronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.y;
+ ElecFieldFromA.z := -sqr(ElectronMass * SpeedOfLight / Hhat)*points[NewScreen]^[xpos,ypos,zpos].PsiVect.z;
+ end;
+ end;
+
+ if field_stats and (pass=1) then begin
+ ElecFieldFromA_Sum:= ElecFieldFromA_Sum + VectSize(ElecFieldFromA);
+ if (xpos <= particle1_x) then ElecFieldFromA_SignedHalf_SumX:= ElecFieldFromA_SignedHalf_SumX + ElecFieldFromA.x;
+ end;
+
+ // Electric Field is: -grad(div) of Psi (grad of ElectricPotential Field) - d/dt of Vector Potential field
+ // In Electric, we already have -grad(div(Psi)), now subtract d/dt of Vector Potential field
+ with points[NewScreen]^[xpos,ypos,zpos].Electric do begin
+ // E = -grad(div(Psi)) - dA/dt
+ x := ElecFieldFromV.x - ElecFieldFromA.x;
+ y := ElecFieldFromV.y - ElecFieldFromA.y;
+ z := ElecFieldFromV.z - ElecFieldFromA.z;
+ end;
+
+ // Note: this can only be selected for electrons/positrons/protons
+ if E_useFormula and not smoothing then begin
+ if two_particles then begin
+ // get actual distance in metres
+ r1:=sqrt( sqr((xpos - particle1_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r1 < r_lower_limit ) then r1:=r_lower_limit; // prevent divide by zero errors
+
+ // get actual distance in metres
+ r2:=sqrt( sqr((xpos - particle2_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r2 < r_lower_limit ) then r2:=r_lower_limit; // prevent divide by zero errors
+
+ if (pass=1) then begin
+ actual_x:=(xpos - particle1_x)*dx;
+ r:=r1;
+ end;
+ if (pass=2) then begin
+ actual_x:=(xpos - particle2_x)*dx;
+ r:=r2;
+ end;
+ end
+ else begin
+ // get actual distance in metres
+ r:=sqrt( sqr(x*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r < r_lower_limit ) then r:=r_lower_limit; // prevent divide by zero errors
+
+ actual_x:=x*dx;
+ end;
+
+ actual_y:=y*dy;
+ actual_z:=z*dz;
+
+ with points[NewScreen]^[xpos,ypos,zpos].Electric do begin
+ if electron then
+ M:=ElectronMass
+ else if positron then
+ M:=PositronMass
+ else if proton then
+ M:=ProtonMass
+ else if neutron then
+ M:=NeutronMass
+ else if neutrino then
+ M:=ElectronNeutrinoMass;
+
+ charge_sign:=1;
+ charge_factor:=1;
+
+ if electron then begin
+ charge_sign:=sign(ElectronCharge);
+ charge_factor:=charge_sign;
+ end
+ else if neutron or neutrino then begin
+ charge_sign:=-1;
+ charge_factor:=sqrt(4/5);
+ end;
+
+ Qsin1 := -charge_factor*UnitaryCharge*sin(theta_const*(Time - charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qcos1 := -charge_factor*UnitaryCharge*cos(theta_const*(Time - charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qsin2 := -charge_factor*UnitaryCharge*sin(theta_const*(Time + charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qcos2 := -charge_factor*UnitaryCharge*cos(theta_const*(Time + charge_sign*r/(SpeedOfLight - x_velocity)));
+
+ c:=SpeedOfLight;
+ E0:=Permittivity;
+
+ // From Maple calculations:
+ //
+ if ( ViewTop ) then begin
+ if neutron or neutrino then begin
+ x:= (((15/8)*Hhat*Qcos1*sqr(actual_x))/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((15/8)*Qsin1*sqr(actual_x))/(Pi*Power(sqr(r),2)*E0) -
+ ((5/8)*Hhat*Qcos1)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((5/8)*Qcos1*M*c*sqr(actual_x))/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((5/8)*Qsin1)/(Pi*sqr(r)*E0) +
+ ((3/4)*Hhat*Qsin1)*(actual_y*actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ ((3/4)*Qcos1)*(actual_x*actual_y)/(Pi*Power(sqr(r),2)*E0) -
+ ((1/4)*Qsin1)*M*c*(actual_x*actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((9/8)*Hhat*Qsin2)*(actual_y*actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((9/8)*Qcos2)*(actual_x*actual_y)/(Pi*Power(sqr(r),2)*E0) -
+ ((3/8)*Qsin2)*M*c*(actual_x*actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ ((5/8)*c*Qcos1*M)/(Pi*r*E0*Hhat));
+
+ y:= (((15/8)*Hhat*Qcos1*(actual_x*actual_y))/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((15/8)*Qsin1*(actual_y*actual_x))/(Pi*Power(sqr(r),2)*E0) -
+ ((5/8)*Qcos1*M*c*(actual_y*actual_x))/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((3/4)*Hhat*Qsin1)*sqr(actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ ((3/4)*Qcos1)*sqr(actual_y)/(Pi*Power(sqr(r),2)*E0) -
+ ((1/4)*Hhat*Qsin1)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((1/4)*Qsin1)*M*c*sqr(actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ ((1/4)*Qcos1)/(Pi*sqr(r)*E0) +
+ ((9/8)*Hhat*Qsin2)*sqr(actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((9/8)*Qcos2*sqr(actual_y))/(Pi*Power(sqr(r),2)*E0) -
+ ((3/8)*Hhat*Qsin2)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((3/8)*Qsin2)*M*c*sqr(actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((3/8)*Qcos2)/(Pi*sqr(r)*E0) -
+ (1/sqr(c))*((1/4)*Power(c,3)*Qsin1*M/(Pi*r*E0*Hhat) +
+ (3/8)*Power(c,3)*Qsin2*M/(Pi*r*E0*Hhat)));
+
+ z:=((15/8)*Hhat*Qcos1*(actual_x*actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (15/8)*Qsin1*(actual_z*actual_x)/(Pi*Power(sqr(r),2)*E0) -
+ (5/8)*Qcos1*M*c*(actual_z*actual_x)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (3/4)*Hhat*Qsin1*(actual_y*actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/4)*Qcos1*(actual_z*actual_y)/(Pi*Power(sqr(r),2)*E0) -
+ (1/4)*Qsin1*M*c*(actual_z*actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (9/8)*Hhat*Qsin2*(actual_y*actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (9/8)*Hhat*Qcos2*(actual_z*actual_y)/(Pi*Power(sqr(r),2)*E0) -
+ (3/8)*Qsin2*M*c*(actual_z*actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat));
+ end
+ else begin
+ x:=-(-(3/2)*Hhat*Qcos2*sqr(actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*sqr(actual_x)/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Hhat*Qcos2/(Pi*Power(sqr(r),(3/2))*M*c*E0) +
+ (1/2)*Qcos2*M*c*sqr(actual_x)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (1/2)*Qsin2/(Pi*sqr(r)*E0) -
+ (3/2)*Hhat*Qsin2*actual_y*actual_x/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*actual_x*actual_y/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qsin2*M*c*actual_x*actual_y/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (1/2)*Qcos2*M*c/(Pi*r*E0*Hhat));
+
+ y:=-(-(3/2)*Hhat*Qcos2*actual_x*actual_y/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*actual_y*actual_x/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qcos2*M*c*actual_y*actual_x/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (3/2)*Hhat*Qsin2*sqr(actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*sqr(actual_y)/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Hhat*Qsin2/(Pi*Power(sqr(r),(3/2))*M*c*E0) +
+ (1/2)*Qsin2*M*c*sqr(actual_y)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (1/2)*Qcos2/(Pi*sqr(r)*E0) +
+ (1/2)*Qsin2*M*c/(Pi*r*E0*Hhat));
+
+ z:=-(-(3/2)*Hhat*Qcos2*actual_x*actual_z/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*actual_z*actual_x/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qcos2*M*c*actual_z*actual_x/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (3/2)*Hhat*Qsin2*actual_y*actual_z/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*actual_z*actual_y/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qsin2*M*c*actual_z*actual_y/(Pi*Power(sqr(r),(3/2))*E0*Hhat));
+ end;
+ end
+ else begin // remap y -> -z and z -> y
+ if neutron or neutrino then begin
+ x:=(((15/8)*Hhat*Qcos1*sqr(actual_x))/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((15/8)*Qsin1*sqr(actual_x))/(Pi*Power(sqr(r),2)*E0) -
+ ((5/8)*Hhat*Qcos1)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((5/8)*Qcos1*M*c*sqr(actual_x))/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((5/8)*Qsin1)/(Pi*sqr(r)*E0) +
+ ((3/4)*Hhat*Qsin1)*(actual_z*actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ ((3/4)*Qcos1)*(actual_x*actual_z)/(Pi*Power(sqr(r),2)*E0) -
+ ((1/4)*Qsin1)*M*c*(actual_x*actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((9/8)*Hhat*Qsin2)*(actual_z*actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((9/8)*Qcos2)*(actual_x*actual_z)/(Pi*Power(sqr(r),2)*E0) -
+ ((3/8)*Qsin2)*M*c*(actual_x*actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ ((5/8)*c*Qcos1*M)/(Pi*r*E0*Hhat));
+
+ y:= (((15/8)*Hhat*Qcos1*(actual_x*actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (15/8)*Qsin1*(actual_y*actual_x)/(Pi*Power(sqr(r),2)*E0) -
+ (5/8)*Qcos1*M*c*(actual_y*actual_x)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (3/4)*Hhat*Qsin1*(actual_z*actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/4)*Qcos1*(actual_y*actual_z)/(Pi*Power(sqr(r),2)*E0) -
+ (1/4)*Qsin1*M*c*(actual_y*actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (9/8)*Hhat*Qsin2*(actual_z*actual_y)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (9/8)*Hhat*Qcos2*(actual_y*actual_z)/(Pi*Power(sqr(r),2)*E0) -
+ (3/8)*Qsin2*M*c*(actual_y*actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat)));
+
+ z:= (((15/8)*Hhat*Qcos1*(actual_x*actual_z))/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((15/8)*Qsin1*(actual_z*actual_x))/(Pi*Power(sqr(r),2)*E0) -
+ ((5/8)*Qcos1*M*c*(actual_z*actual_x))/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((3/4)*Hhat*Qsin1)*sqr(actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ ((3/4)*Qcos1)*sqr(actual_z)/(Pi*Power(sqr(r),2)*E0) -
+ ((1/4)*Hhat*Qsin1)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((1/4)*Qsin1)*M*c*sqr(actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ ((1/4)*Qcos1)/(Pi*sqr(r)*E0) +
+ ((9/8)*Hhat*Qsin2)*sqr(actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ ((9/8)*Qcos2*sqr(actual_z))/(Pi*Power(sqr(r),2)*E0) -
+ ((3/8)*Hhat*Qsin2)/(Pi*Power(sqr(r),(3/2))*M*c*E0) -
+ ((3/8)*Qsin2)*M*c*sqr(actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ ((3/8)*Qcos2)/(Pi*sqr(r)*E0) -
+ (1/sqr(c))*((1/4)*Power(c,3)*Qsin1*M/(Pi*r*E0*Hhat) +
+ (3/8)*Power(c,3)*Qsin2*M/(Pi*r*E0*Hhat)));
+ end
+ else begin // remap y -> -z and z -> y
+ x:=-(-(3/2)*Hhat*Qcos2*sqr(actual_x)/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*sqr(actual_x)/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Hhat*Qcos2/(Pi*Power(sqr(r),(3/2))*M*c*E0) +
+ (1/2)*Qcos2*M*c*sqr(actual_x)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (1/2)*Qsin2/(Pi*sqr(r)*E0) -
+ (3/2)*Hhat*Qsin2*actual_z*actual_x/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*actual_x*actual_z/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qsin2*M*c*actual_x*actual_z/(Pi*Power(sqr(r),(3/2))*E0*Hhat) +
+ (1/2)*Qcos2*M*c/(Pi*r*E0*Hhat));
+
+ y:=-(-(3/2)*Hhat*Qcos2*actual_x*actual_y/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*actual_y*actual_x/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qcos2*M*c*actual_y*actual_x/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (3/2)*Hhat*Qsin2*actual_z*actual_y/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*actual_y*actual_z/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qsin2*M*c*actual_y*actual_z/(Pi*Power(sqr(r),(3/2))*E0*Hhat));
+
+ z:=-(-(3/2)*Hhat*Qcos2*actual_x*actual_z/(Pi*Power(sqr(r),(5/2))*M*c*E0) -
+ (3/2)*Qsin2*actual_z*actual_x/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Qcos2*M*c*actual_z*actual_x/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (3/2)*Hhat*Qsin2*sqr(actual_z)/(Pi*Power(sqr(r),(5/2))*M*c*E0) +
+ (3/2)*Qcos2*sqr(actual_z)/(Pi*Power(sqr(r),2)*E0) +
+ (1/2)*Hhat*Qsin2/(Pi*Power(sqr(r),(3/2))*M*c*E0) +
+ (1/2)*Qsin2*M*c*sqr(actual_z)/(Pi*Power(sqr(r),(3/2))*E0*Hhat) -
+ (1/2)*Qcos2/(Pi*sqr(r)*E0) +
+ (1/2)*Qsin2*M*c/(Pi*r*E0*Hhat));
+ end;
+ end;
+ end;
+ end;
+
+ if field_stats and (pass=1) then ElecField_Sum:= ElecField_Sum + VectSize(points[NewScreen]^[xpos,ypos,zpos].Electric);
+ end;
+ end;
+ end; // end {scan grid's x coords}
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+ x:= xpos - midx;
+ y:= ypos - midy;
+ z:= zpos - midz;
+
+ if two_particles then begin
+ // get actual distance in metres
+ r1:=sqrt( sqr((xpos - particle1_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r1 < r_lower_limit ) then r1:=r_lower_limit; // prevent divide by zero errors
+
+ // get actual distance in metres
+ r2:=sqrt( sqr((xpos - particle2_x)*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r2 < r_lower_limit ) then r2:=r_lower_limit; // prevent divide by zero errors
+
+ if (pass=1) then begin
+ actual_x:=(xpos - particle1_x)*dx;
+ r:=r1;
+ end;
+ if (pass=2) then begin
+ actual_x:=(xpos - particle2_x)*dx;
+ r:=r2;
+ end;
+ end
+ else begin
+ // get actual distance in metres
+ r:=sqrt( sqr(x*dx) + sqr(y*dy) + sqr(z*dz) );
+ if ( r < r_lower_limit ) then r:=r_lower_limit; // prevent divide by zero errors
+
+ actual_x:=x*dx;
+ end;
+
+ actual_y:=y*dy;
+ actual_z:=z*dz;
+
+ ThisGroup:=PointGroup(scr, xpos, ypos, zpos);
+ NewGroup:=PointGroup(NewScreen, xpos, ypos, zpos);
+
+ // Calculate Magnetic B Field
+ with points[NewScreen]^[xpos,ypos,zpos].Magnetic do begin
+
+ // Note: this can only be selected for electrons/positrons/protons
+ if H_useFormula and not smoothing then begin
+ if (pass=1) then particle_1_2_B[xpos,ypos,zpos]:=NullVect;
+ if (pass=3) then begin
+ x:=particle_1_2_B[xpos,ypos,zpos].x;
+ y:=particle_1_2_B[xpos,ypos,zpos].y;
+ z:=particle_1_2_B[xpos,ypos,zpos].z;
+ end
+ else begin
+ if electron then
+ M:=ElectronMass
+ else if positron then
+ M:=PositronMass
+ else if proton then
+ M:=ProtonMass
+ else if neutron then
+ M:=NeutronMass
+ else if neutrino then
+ M:=ElectronNeutrinoMass;
+
+ charge_sign:=1;
+ charge_factor:=1;
+
+ if electron then begin
+ charge_sign:=sign(ElectronCharge);
+ end
+ else if neutron or neutrino then begin
+ charge_sign:=-1;
+ charge_factor:=sqrt(4/5);
+ end;
+
+ Qsin1 := -charge_factor*UnitaryCharge*sin(theta_const*(Time - charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qcos1 := -charge_factor*UnitaryCharge*cos(theta_const*(Time - charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qsin2 := -charge_factor*UnitaryCharge*sin(theta_const*(Time + charge_sign*r/(SpeedOfLight - x_velocity)));
+ Qcos2 := -charge_factor*UnitaryCharge*cos(theta_const*(Time + charge_sign*r/(SpeedOfLight - x_velocity)));
+
+ c:=SpeedOfLight;
+ E0:=Permittivity;
+
+ // From Maple calculations:
+ //
+ // B = Curl(A)
+ //
+ if ( ViewTop ) then begin
+ if neutron or neutrino then begin
+ x:=-(5/8)*Qcos1/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (5/8)*Qsin1*M/(Pi*sqr(r)*E0*Hhat);
+
+ y:=(1/sqr(c))*(-(1/4)*c*Qsin1/(Pi*Power(sqr(r),(3/2))*E0) +
+ (1/4)*sqr(c)*Qcos1*M/(Pi*sqr(r)*E0*Hhat) -
+ (3/8)*c*Qsin2/(Pi*Power(sqr(r),(3/2))*E0) -
+ (3/8)*sqr(c)*Qcos2*M/(Pi*sqr(r)*E0*Hhat));
+
+ z:=-(x*actual_x + y*actual_y);
+
+ x:=x*actual_z;
+ y:=y*actual_z;
+ end
+ // For charged particles (electron, positron, proton):
+ else begin
+ x:=-((1/2)*Qcos2*actual_z/(c*Pi*Power(sqr(r),(3/2))*E0) +
+ (1/2)*Qsin2*M*actual_z/(Pi*sqr(r)*E0*Hhat));
+
+ y:=-((1/2)*Qsin2*actual_z/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (1/2)*Qcos2*M*actual_z/(Pi*sqr(r)*E0*Hhat));
+
+ z:=-(-(1/2)*Qcos2*actual_x/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (1/2)*Qsin2*M*actual_x/(Pi*sqr(r)*E0*Hhat) -
+ (1/2)*Qsin2*actual_y/(c*Pi*Power(sqr(r),(3/2))*E0) +
+ (1/2)*Qcos2*M*actual_y/(Pi*sqr(r)*E0*Hhat));
+
+ end;
+ end
+ else begin // remap x -> -x, y -> -z and z -> -y
+ if neutron or neutrino then begin
+ x:=-(5/8)*Qcos1/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (5/8)*Qsin1*M/(Pi*sqr(r)*E0*Hhat);
+
+ z:=(1/sqr(c))*(-(1/4)*c*Qsin1/(Pi*Power(sqr(r),(3/2))*E0) +
+ (1/4)*sqr(c)*Qcos1*M/(Pi*sqr(r)*E0*Hhat) -
+ (3/8)*c*Qsin2/(Pi*Power(sqr(r),(3/2))*E0) -
+ (3/8)*sqr(c)*Qcos2*M/(Pi*sqr(r)*E0*Hhat));
+
+ y:=(x*actual_x + y*actual_z);
+
+ x:=-x*actual_y;
+ z:=-z*actual_y;
+ end
+ else begin // remap x -> -x, y -> -z and z -> -y
+ x:= ((1/2)*Qcos2*actual_y/(c*Pi*Power(sqr(r),(3/2))*E0) +
+ (1/2)*Qsin2*M*actual_y/(Pi*sqr(r)*E0*Hhat));
+
+ y:= (-(1/2)*Qcos2*actual_x/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (1/2)*Qsin2*M*actual_x/(Pi*sqr(r)*E0*Hhat) -
+ (1/2)*Qsin2*actual_z/(c*Pi*Power(sqr(r),(3/2))*E0) +
+ (1/2)*Qcos2*M*actual_z/(Pi*sqr(r)*E0*Hhat));
+
+ z:= ((1/2)*Qsin2*actual_y/(c*Pi*Power(sqr(r),(3/2))*E0) -
+ (1/2)*Qcos2*M*actual_y/(Pi*sqr(r)*E0*Hhat));
+ end;
+ end;
+
+ // if the second particle is a positron, we must reverse the direction of the magnetic field vector, as
+ // the above equation is for an electron.
+ if ((maxpass = 1) or ((maxpass > 1) and (pass = 2))) and (positron or proton) then begin
+ x:=-x;
+ y:=-y;
+ z:=-z;
+ end;
+
+ // Double B magnitude (due to two equal components of B)
+ x:=2*x;
+ y:=2*y;
+ z:=2*z;
+
+ particle_1_2_B[xpos,ypos,zpos].x := particle_1_2_B[xpos,ypos,zpos].x + x;
+ particle_1_2_B[xpos,ypos,zpos].y := particle_1_2_B[xpos,ypos,zpos].y + y;
+ particle_1_2_B[xpos,ypos,zpos].z := particle_1_2_B[xpos,ypos,zpos].z + z;
+ end;
+ end
+ else begin
+ // Magnetic Field is Curl of Vector Potential Field
+ VectGrp:=VectorGroup(NewGroup, VECTOR_POTENTIAL_FIELD);
+ CurlVect:=VectCurl(VectGrp);
+
+ x:=CurlVect.x;
+ y:=CurlVect.y;
+ z:=CurlVect.z;
+
+ // Double B magnitude (due to two equal components of B)
+ x:=2*x;
+ y:=2*y;
+ z:=2*z;
+ end;
+ end;
+ if field_stats and (pass=1) then MagField_Sum:= MagField_Sum + VectSize(points[NewScreen]^[xpos,ypos,zpos].Magnetic);
+ end;
+ end;
+ end; // end {scan grid's x coords}
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ // Calculate the E and B field energies for each of the two particles,
+ // then sum them for pass 3 when both particles are present simultaneously.
+ if ((pass=1) or (pass=2)) then begin
+ UpdateE_Energy(NewScreen);
+ UpdateB_Energy(NewScreen);
+ E_Energy_Sum := E_Energy_Sum + E_Energy_Tot;
+ B_Energy_Sum := B_Energy_Sum + B_Energy_Tot;
+ end
+ else begin
+ E_Energy_Tot := E_Energy_Sum;
+ B_Energy_Tot := B_Energy_Sum;
+ end;
+
+ if EnergyCorrection then begin
+ if ((pass=1) or (pass=2)) then
+ EnergyFactor:=0.5
+ else
+ EnergyFactor:=1;
+
+ PowerCorrectionFactor_E:=1;
+ PowerCorrectionFactor_B:=1;
+
+ if proton then begin
+ if (E_Energy_Tot > 0) then PowerCorrectionFactor_E:=sqrt((EnergyFactor*ProtonMass*SpeedOfLight*SpeedOfLight)/E_Energy_Tot); // correct for model inaccuracy
+ if (B_Energy_Tot > 0) then PowerCorrectionFactor_B:=sqrt((EnergyFactor*ProtonMass*SpeedOfLight*SpeedOfLight)/B_Energy_Tot); // correct for model inaccuracy
+ end
+ else if neutron then begin
+ if (E_Energy_Tot > 0) then PowerCorrectionFactor_E:=sqrt((EnergyFactor*NeutronMass*SpeedOfLight*SpeedOfLight)/E_Energy_Tot); // correct for model inaccuracy
+ if (B_Energy_Tot > 0) then PowerCorrectionFactor_B:=sqrt((EnergyFactor*NeutronMass*SpeedOfLight*SpeedOfLight)/B_Energy_Tot); // correct for model inaccuracy
+ end
+ else if quark_up then begin
+ if (E_Energy_Tot > 0) then PowerCorrectionFactor_E:=sqrt((EnergyFactor*UpQuarkMass*SpeedOfLight*SpeedOfLight)/E_Energy_Tot); // correct for model inaccuracy
+ if (B_Energy_Tot > 0) then PowerCorrectionFactor_B:=sqrt((EnergyFactor*UpQuarkMass*SpeedOfLight*SpeedOfLight)/B_Energy_Tot); // correct for model inaccuracy
+ end
+ else if quark_down then begin
+ if (E_Energy_Tot > 0) then PowerCorrectionFactor_E:=sqrt((EnergyFactor*DownQuarkMass*SpeedOfLight*SpeedOfLight)/E_Energy_Tot); // correct for model inaccuracy
+ if (B_Energy_Tot > 0) then PowerCorrectionFactor_B:=sqrt((EnergyFactor*DownQuarkMass*SpeedOfLight*SpeedOfLight)/B_Energy_Tot); // correct for model inaccuracy
+ end
+ else begin
+ if (E_Energy_Tot > 0) then PowerCorrectionFactor_E:=sqrt((EnergyFactor*ElectronMass*SpeedOfLight*SpeedOfLight)/E_Energy_Tot); // correct for model inaccuracy
+ if (B_Energy_Tot > 0) then PowerCorrectionFactor_B:=sqrt((EnergyFactor*ElectronMass*SpeedOfLight*SpeedOfLight)/B_Energy_Tot); // correct for model inaccuracy
+ end;
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+
+ with points[NewScreen]^[xpos,ypos,zpos].Electric do begin
+ x:=x*PowerCorrectionFactor_E;
+ y:=y*PowerCorrectionFactor_E;
+ z:=z*PowerCorrectionFactor_E;
+ end;
+
+ with points[NewScreen]^[xpos,ypos,zpos].Magnetic do begin
+ x:=x*PowerCorrectionFactor_B;
+ y:=y*PowerCorrectionFactor_B;
+ z:=z*PowerCorrectionFactor_B;
+ end;
+
+ if two_particles then begin
+ if (pass=1) then begin
+ particle1_A[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].VectorPotential;
+ particle1_E[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].Electric;
+ end
+ else if (pass=2) then begin
+ particle2_A[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].VectorPotential;
+ particle2_E[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].Electric;
+ end;
+ end;
+ end;
+ end;
+ end; // end {scan grid's x coords}
+
+ UpdateE_Energy(NewScreen);
+ UpdateB_Energy(NewScreen);
+ end; // end if (EnergyCorrection = 1)
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+
+ ThisGroup:=PointGroup(scr, xpos, ypos, zpos);
+ NewGroup:=PointGroup(NewScreen, xpos, ypos, zpos);
+
+ with points[NewScreen]^[xpos,ypos,zpos] do begin
+ VectGrp:=VectorGroup(NewGroup, ELECTRIC_FIELD);
+ ChargeDensity:=-Permittivity*VectDiv(VectGrp);
+ end;
+
+ if two_particles then begin
+ if (pass=1) then begin
+ if not EnergyCorrection then begin
+ particle1_A[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].VectorPotential;
+ particle1_E[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].Electric;
+ end;
+ particle1_Power[xpos, ypos, zpos]:=RMS_PowerFlow(NewGroup.P0);
+ end
+ else if (pass=2) then begin
+ if not EnergyCorrection then begin
+ particle2_A[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].VectorPotential;
+ particle2_E[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].Electric;
+ end;
+ particle2_Power[xpos, ypos, zpos]:=RMS_PowerFlow(NewGroup.P0);
+ end;
+ end // end if (two_particles)
+ else begin
+ particle1_A[xpos,ypos,zpos]:=points[NewScreen]^[xpos,ypos,zpos].VectorPotential;
+ end;
+ end;
+ end;
+ end; // end {scan grid's x coords}
+ end; //if Flip_YZ
+ end; // end: for pass := 1 to maxpass do begin
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + 2;
+ update_progress_bar(progress);
+
+ if two_particles then begin
+ c1:=0;
+ c2:=0;
+ c3:=0;
+ PowerCount_neg:=0;
+ PowerSum_neg:=0;
+ PowerCount_pos:=0;
+ PowerSum_pos:=0;
+
+ for xpos:=0 to GridWidth-1 do begin {scan grid's x coords}
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ for ypos:=0 to GridHeight-1 do begin {scan grid's y coords}
+ for zpos:=0 to GridDepth-1 do begin {scan grid's z coords}
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ points[NewScreen]^[xpos,ypos,zpos].particle_pos_Reflected := NullVect;
+ points[NewScreen]^[xpos,ypos,zpos].particle_neg_Reflected := NullVect;
+
+ dot_v1v2:=VectorDot(particle1_Power[xpos, ypos, zpos], particle2_Power[xpos, ypos, zpos]);
+
+ vect.x:=min(abs(particle1_Power[xpos, ypos, zpos].x),abs(particle2_Power[xpos, ypos, zpos].x));
+ vect.y:=min(abs(particle1_Power[xpos, ypos, zpos].y),abs(particle2_Power[xpos, ypos, zpos].y));
+ vect.z:=min(abs(particle1_Power[xpos, ypos, zpos].z),abs(particle2_Power[xpos, ypos, zpos].z));
+
+ vect2.x:=1 * sign(particle1_Power[xpos, ypos, zpos].x) * sign(particle2_Power[xpos, ypos, zpos].x);
+ vect2.y:=1 * sign(particle1_Power[xpos, ypos, zpos].y) * sign(particle2_Power[xpos, ypos, zpos].y);
+ vect2.z:=1 * sign(particle1_Power[xpos, ypos, zpos].z) * sign(particle2_Power[xpos, ypos, zpos].z);
+
+ if vect2.x < 0 then points[NewScreen]^[xpos,ypos,zpos].particle_neg_Reflected.x := -2*sign(particle1_Power[xpos, ypos, zpos].x)*vect.x;
+ if vect2.y < 0 then points[NewScreen]^[xpos,ypos,zpos].particle_neg_Reflected.y := -2*sign(particle1_Power[xpos, ypos, zpos].y)*vect.y;
+ if vect2.z < 0 then points[NewScreen]^[xpos,ypos,zpos].particle_neg_Reflected.z := -2*sign(particle1_Power[xpos, ypos, zpos].z)*vect.z;
+
+ if vect2.x > 0 then points[NewScreen]^[xpos,ypos,zpos].particle_pos_Reflected.x := 2*sign(particle1_Power[xpos, ypos, zpos].x)*vect.x;
+ if vect2.y > 0 then points[NewScreen]^[xpos,ypos,zpos].particle_pos_Reflected.y := 2*sign(particle1_Power[xpos, ypos, zpos].y)*vect.y;
+ if vect2.z > 0 then points[NewScreen]^[xpos,ypos,zpos].particle_pos_Reflected.z := 2*sign(particle1_Power[xpos, ypos, zpos].z)*vect.z;
+
+ // if not in the space between particles, reverse the sign of the reflected force
+ if not ((xpos > particle1_x) and (xpos < particle2_x)) then with points[NewScreen]^[xpos,ypos,zpos] do begin
+ particle_pos_Reflected.x := -particle_pos_Reflected.x;
+ particle_pos_Reflected.y := -particle_pos_Reflected.y;
+ particle_pos_Reflected.z := -particle_pos_Reflected.z;
+
+ particle_neg_Reflected.x := -particle_neg_Reflected.x;
+ particle_neg_Reflected.y := -particle_neg_Reflected.y;
+ particle_neg_Reflected.z := -particle_neg_Reflected.z;
+ end;
+ {$IFEND}
+ Power_x1:=particle1_Power[xpos, ypos, zpos].x;
+ Power_x2:=particle2_Power[xpos, ypos, zpos].x;
+
+ vect:=particle1_E[xpos,ypos,zpos];
+ vect2:=particle2_E[xpos,ypos,zpos];
+ vect.x:=0;
+ vect2.x:=0;
+ vect:=Normalize(vect);
+ vect2:=Normalize(vect2);
+ dot_v1v2:=abs(VectorDot(vect,vect2));
+
+ ReflectedPowerAtPoint:=0;
+
+ // Opposing Poynting vectors reflect off one another, so energy equal to the minimum magnitude of the two opposing vectors
+ // reflects on each side of the meeting point. Also, for relected EM energy the force on each particle is twice that of absorption,
+ // so each side of the relection point has a force equal to twice of the minimum magnitude of the two opposing vectors.
+ //
+ // For two particles with the same charge (two electrons or two positrons) the opposing vectors are in between the two particles, so the
+ // force on each particle is outwards (away from the other particle). For two particles with opposite charges (an electron and a positron),
+ // the opposing vectors are in the space on the outside of each particle (i.e. not in the space between the particle centers), thus the force
+ // in this case is inwards for each particle (towards the other particle).
+ //
+ // For particles with the same charge:
+ //
+ // If |B1| is the magnitude of the total amount of power in Poynting vectors that are in opposition,
+ // |C1| is the total amount of power in Poynting vectors that are in the same direction, |P1| is the total power,
+ // A1 is the acceleration of each particle away from the other, and k is a constant of proportionality for the
+ // resulting acceleration due to an amount of reflected power:
+ //
+ // |P1| = |B1| + |C1|
+ // A1 = k*B1
+ //
+ // Similarly for particles with the opposite charge, but with the directions reversed:
+ // B2 is the total amount of power in Poynting vectors that are in the same direction,
+ // C2 is the total amount of power in Poynting vectors that are in opposition, P2 is the total power,
+ // A2 is the acceleration of each particle away from the other, and k is a constant of proportionality for the
+ // resulting acceleration due to an amount of reflected power:
+ //
+ // |P2| = |B2| + |C2|
+ // A2 = k*C2
+ //
+ // So, as B1 is the amount of power for vectors that are in opposition (in the space between particles),
+ // and as the vector fields in both cases (like charges and opposite charges) are the same except that in the second
+ // case the vectors for the 2nd particle are reversed, we can say that:
+ //
+ // |B2| = |B1|,
+ //
+ // and therefore:
+
+ // |C2| = |C1| also.
+ //
+ // Thus:
+ //
+ // |P2| = |B1| + |C1|
+ //
+ // Therefore, the amount of acceleration two oppositely charged particles experience towards each other is proportional
+ // to the amount of power for Poynting vectors in the same direction (in the space between the particles), as well as
+ // being proportional to the amount of power in opposing vectors in the space outside the particles.
+
+ // The Force imparted upon reflection is double the incident radiation pressure
+ reflected_power:=2*dot_v1v2*min(abs(Power_x1),abs(Power_x2));
+
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_sum1 := analysis_results[StartOption][IterationCount].power_sum1 + abs(Power_x1);
+ analysis_results[StartOption][IterationCount].power_sum2 := analysis_results[StartOption][IterationCount].power_sum2 + abs(Power_x2);
+ analysis_results[StartOption][IterationCount].reflected_sum := analysis_results[StartOption][IterationCount].reflected_sum + reflected_power;
+ end;
+
+ // if two oppositely charged particles, reverse the sign (charge) of one particle in order to calculate the
+ // repulsion between particles (rather than attraction), then convert this (at the bottom) to a repulsion.
+ // This is appropriate as the amount of attraction between oppositely charged particles is the same as the
+ // amount of repulsion between particles with the same charge (see explanation above).
+ if (electron and positron) then Power_x2:=-Power_x2;
+
+ if ((Power_x1 > 0) and (Power_x2 < 0)) then begin
+ if (xpos > particle1_x) and (xpos < particle2_x) then begin
+ ReflectedPowerAtPoint:=ReflectedPowerAtPoint - reflected_power;
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_reflected_1_sum1 := analysis_results[StartOption][IterationCount].power_reflected_1_sum1 + 2*reflected_power;
+ end;
+ end
+ else begin
+ ReflectedPowerAtPoint:=ReflectedPowerAtPoint + reflected_power;
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_reflected_1_sum2 := analysis_results[StartOption][IterationCount].power_reflected_1_sum2 + 2*reflected_power;
+ end;
+ end;
+
+ c1:=c1+ReflectedPowerAtPoint*PointArea/10000;
+
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_opposed_1_sum1 := analysis_results[StartOption][IterationCount].power_opposed_1_sum1 + Power_x1;
+ analysis_results[StartOption][IterationCount].power_opposed_1_sum2 := analysis_results[StartOption][IterationCount].power_opposed_1_sum2 + Power_x2;
+ end;
+ end
+ else if ((Power_x1 < 0) and (Power_x2 > 0)) then begin
+ if (xpos > particle1_x) and (xpos < particle2_x) then begin
+ ReflectedPowerAtPoint:=ReflectedPowerAtPoint - reflected_power;
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_reflected_2_sum1 := analysis_results[StartOption][IterationCount].power_reflected_2_sum1 + 2*reflected_power;
+ end;
+ end
+ else begin
+ ReflectedPowerAtPoint:=ReflectedPowerAtPoint + reflected_power;
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_reflected_2_sum2 := analysis_results[StartOption][IterationCount].power_reflected_2_sum2 + 2*reflected_power;
+ end;
+ end;
+
+ c2:=c2+ReflectedPowerAtPoint*PointArea/10000;
+
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_opposed_2_sum1 := analysis_results[StartOption][IterationCount].power_opposed_2_sum1 + Power_x1;
+ analysis_results[StartOption][IterationCount].power_opposed_2_sum2 := analysis_results[StartOption][IterationCount].power_opposed_2_sum2 + Power_x2;
+ end;
+ end
+ else begin
+ if (Power_x1 < Power_x2) then begin
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_aligned_1_sum1 := analysis_results[StartOption][IterationCount].power_aligned_1_sum1 + Power_x1;
+ analysis_results[StartOption][IterationCount].power_aligned_1_sum2 := analysis_results[StartOption][IterationCount].power_aligned_1_sum2 + Power_x2;
+ end;
+ end
+ else begin
+ if two_particle_analysis then begin
+ analysis_results[StartOption][IterationCount].power_aligned_2_sum1 := analysis_results[StartOption][IterationCount].power_aligned_2_sum1 + Power_x1;
+ analysis_results[StartOption][IterationCount].power_aligned_2_sum2 := analysis_results[StartOption][IterationCount].power_aligned_2_sum2 + Power_x2;
+ end;
+ end;
+ end;
+
+ // if oppositely charges particles, now reverse the force, as the opposite charges were converted into
+ // alike charges (see explanation above) in order to calculate the repulsion, which is then converted
+ // into an attraction (as the two magnitudes are equivalent).
+ if (electron and positron) then begin
+ if ReflectedPowerAtPoint < 0 then begin
+ Inc(PowerCount_neg);
+ PowerSum_neg:=PowerSum_neg - ReflectedPowerAtPoint;
+ end
+ else begin
+ Inc(PowerCount_pos);
+ PowerSum_pos:=PowerSum_pos - ReflectedPowerAtPoint;
+ end;
+ end
+ else begin
+ if ReflectedPowerAtPoint < 0 then begin
+ Inc(PowerCount_neg);
+ PowerSum_neg:=PowerSum_neg + ReflectedPowerAtPoint;
+ end
+ else begin
+ Inc(PowerCount_pos);
+ PowerSum_pos:=PowerSum_pos + ReflectedPowerAtPoint;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ Application.ProcessMessages;
+ if Restart then exit;
+
+ progress:=progress + progress_inc;
+ update_progress_bar(progress);
+
+ // The amount of power coupling between the two particles (electrons) depends on the amount of reflection
+ // of the waves from each particle. This amount depends on the minimum power of the two interacting waves
+ // along the axis connecting the two particle centers (the x axis in this model), as the waves can only reflect
+ // when equal but opposite EM wave components meet at the reflection point.
+ //
+ // Then there is an additional factor that determines the amount of power coupling between the two
+ // particles - the relative orientations of the polarizations of the two waves & how much they align
+ // and thus reflect off each other. As the interface area between the two electrons is a circle,
+ // the amount of coupling between the two EM waves will vary sinusoidally (around this circle)
+ // with the angle difference between the polarizations of the two waves. To get an average of this
+ // sinusoid over the whole circular interface area we must use the RMS of the Electric energy density for
+ // each electron, which is the maximum EM field value (when both polarizations are aligned) divided by √2.
+ //
+ // RMS of ue around the interface circle:
+ // = ue/√2 = ((1/4)*ε0*E^2)/√2
+ //
+ // sin x
+ // |
+ // 1 ,|, _....._
+ // | ,=" "=.
+ // | ," ".
+ // |," , "., , ,
+ // ""*""""""""""|""""""""""|."""""""""|""""""""".|"""">
+ // | π ". ." 2π x
+ // | "._ _,"
+ // | "-.....-"
+ // -1 ,|,
+ // |
+ //
+ // RMS(sin x)
+ // |
+ // 1 ,|,
+ // 1/√2 ,|--------------------------------------------
+ // |
+ // | , , , ,
+ // ""*""""""""""|""""""""""|""""""""""|""""""""""|"""">
+ // | π 2π x
+ // |
+ //-1/√2 ,|,
+ // -1 ,|,
+ // |
+ //
+ // As these values are instantaneous the RMS of these values must be taken to get the actual, effective value;
+ // however, when calculating the amount of reflected energy between the two wave-functions I take the Dot Product
+ // of the two Electric field vectors. This process accounts for this angle variation between the two EM waves, and
+ // determines the amount of reflection that occurs.
+ //
+ // The power values of each EM wave are calculated from the Poynting Vector (vector cross product) of the
+ // instantaneous Electric and Magnetic field values of the minimum power of the two interacting waves at each point.
+ //
+ // Electric energy density ue=(1/2)*ε0*ε^2rms
+ //
+ // However, as the wave-function is sinusoidal in all three dimensions the RMS must be taken over 3 cartesian coordinate
+ // dimensions (x, y, z), :
+ //
+ // So, when combined with the (1/2) factor seen above, the actual Electric energy density becomes:
+ //
+ // ∴ ue = (1/2)*ε0*(1/√2 * 1/√2 * 1/√2 * ε)^2 = (1/16)*ε0*ε^2
+ //
+ // The Power value obtained is then converted into a pressure by dividing by the speed of light.
+ //
+ // To work out the actual force between the two particles we need to simplify the calculation by reducing each particle
+ // to a point particle at its wave-function center, with an effective area of interaction of one grid point in the model.
+ // The force between them is due to wave reflections at the mid-way point between them - where waves from each side are equal.
+ //
+ // In a similar way to the Shell Theorem for gravity, where the force between two bodies due to the mass of one spherical
+ // body can be treated as all coming from a single point at that spherical body's center, the attractive/repulsive force
+ // between charged particles can be treated similarly.
+ //
+ // If we start from the situation where both particles are together at the same point, then there is a single grid point of
+ // area interacting between them. As the particles move apart, the volume of the sphere from each particle's center to the
+ // mid-way point between them represents all of the contributing grid points to the total force attributed to the central point.
+ // So, in order to keep the area of interaction between the particles as one grid point of area, in the calculation we must
+ // divide by the rate of increase in volume (V) of the sphere with the distance from the mid-way point (R), which is dV/dR.
+ // As the volume of a sphere is (4/3)πR^3, dV/dR = 4πR^2. Then expressing this in terms of the separation distance (r) between
+ // the particles (r = 2R), we have 4πR^2 = 4π(r/2)^2 = πr^2
+ //
+ // Once this has been done, the actual force between the two particles can be determined by multiplying this pressure by the
+ // area of a single grid point.
+
+ // Total Pressure = The sum of both the Positive & Negative Power divided by speed of light
+ Pressure:=(PowerSum_neg + PowerSum_pos)/SpeedOfLight;
+
+ // The actual pressure at a single, central grid point is 1/πr^2, where r is the number of grid points between the two
+ // particle centers.
+ Pressure:=Pressure/(Pi*sqr(GridWidth*p1_p2_diff*dx/ActualWidth));
+
+ // Total force is pressure * the area of 1 point
+ Force:= Pressure*PointArea;
+
+ Accel:=Force/ElectronMass; // F = m*a
+ Velocity:=Velocity + Accel*TimeStep;
+
+ // e.g.
+ //
+ // For num points = 220x220x220
+ // ActualWidth = 3.02E-11
+ //
+ // r = 0.3 ActualWidth
+ //
+ // r = 3.02e-11 * 2.4 / 8 = 9.06E-12
+ //
+ // r^2 = 8.20836e-23
+ //
+ // q = 1.60217662e-19
+ //
+ // q^2 = 2.5669699216746244e-38
+ //
+ // q^2 / r^2 = 3.12726284138929627842833403993e-16
+ //
+ // k = 8.9875517873681764e9
+ //
+ // F = k (q^2 / r^2) = 8.9875517873681764e9 * 3.12726284138929627842833403993e-16 = 2.8106436739698451704657505254331e-6
+ //
+ // F = m*a
+ //
+ // m = 9.1093835611e-31
+ //
+ // a = 2.8106436739698451704657505254331e-6 / 9.1093835611e-31 = 3.0854378401324523962093223812502e24
+ //
+
+ ExpectedAccel:=0;
+
+ if proton then begin
+ ExpectedAccel := sqr(ProtonCharge)/sqr(ActualWidth*(p1_p2_diff/GridWidth));
+ ExpectedAccel := ExpectedAccel * Ek/ProtonMass;
+ end
+ else begin
+ ExpectedAccel := sqr(ElectronCharge)/sqr(ActualWidth*(p1_p2_diff/GridWidth));
+ ExpectedAccel := ExpectedAccel * Ek/ElectronMass;
+ end;
+
+ // set the sign for the acceleration based on the particles being modeled
+ if not (electron and positron) then ExpectedAccel := -ExpectedAccel;
+ if not (ShowEnergy_CheckBox.Checked) then Energy3.Text:=FloatToStr(ExpectedAccel)
+ else Energy3.Text:=FloatToStr(E_Energy_Tot+B_Energy_Tot); {display total field energy}
+
+ // if not running a profile at the moment, update the particles' positions based on the current acceleration.
+ if two_particle_accel_profile_done then begin
+ particle1_x:=particle1_x + (GridWidth/ActualWidth)*Velocity*TimeStep;
+ particle2_x:=particle2_x - (GridWidth/ActualWidth)*Velocity*TimeStep;
+ end;
+
+ // disable running averaqe - always show current acceleration calculation
+ if false and (IterationCount >= 8) then begin
+ accel_avg:=RunningAverage(min(IterationCount - 8, 108), accel_avg, Accel);
+ if not (ShowEnergy_CheckBox.Checked) then Energy4.Text:=FloatToStr(accel_avg);
+ end
+ else begin
+ if not (ShowEnergy_CheckBox.Checked) then Energy4.Text:=FloatToStr(Accel);
+ end;
+
+ if two_particle_analysis then begin
+ AnalysisSaveResults(StartOption, IterationCount);
+ AnalysisWriteResults(StartOption, IterationCount);
+ end;
+
+ Inc(IterationCount);
+// Energy3.Text:=IntToStr(Trunc(c1)) + ' ' + IntToStr(Trunc(c2)) + ' ' + IntToStr(Trunc(c3));
+
+ progress:=progress + 2;
+ update_progress_bar(progress);
+
+ if profile_changed and not two_particle_accel_profile_done then begin
+ // Close the currently open files
+ if IsOpen(myFile) then CloseFile(myFile);
+ if IsOpen(myFile2) then CloseFile(myFile2);
+ end;
+
+ if two_particle_accel_profile then begin
+ if profile_changed then begin
+ // Try to open the Analysis.txt file for writing to
+ AssignFile(myFile, 'AccelProfile_' + FloatToStrf(PercentBetweenParticles,ffFixed,4,2) + '%_' + FloatToStrf(ActualWidth,ffExponent,5,2) + 'm_' + IntToStr(StartOption) + '.txt');
+ ReWrite(myFile);
+ AssignFile(myFile2, 'AccelProfile_Summary_' + FloatToStrf(PercentBetweenParticles,ffFixed,4,2) + '%_' + FloatToStrf(ActualWidth,ffExponent,5,2) + 'm_' + IntToStr(StartOption) + '.txt');
+ ReWrite(myFile2);
+
+ New_GridWidth:=100;
+ New_GridHeight:=100;
+ New_GridDepth:=100;
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ WriteLn(myFile, 'Grid size ' + IntToStr(GridWidth) + ', (' + FloatToStrf(PercentBetweenParticles,ffFixed,4,2) + '%) : Accel is ' + FloatToStr(Accel) + ' (' + FloatToStr(100*Accel/ExpectedAccel) + '% of expected accel ' + FloatToStr(ExpectedAccel) + ')');
+ WriteLn(myFile, 'E Energy = ' + FloatToStrf(E_Energy_Tot,ffExponent,5,2) + ', B Energy = ' + FloatToStrf(B_Energy_Tot,ffExponent,5,2) + ', Energy Total = ' + FloatToStrf((E_Energy_Tot + B_Energy_Tot),ffExponent,5,2) + ' : ' + FloatToStr(100*(E_Energy_Tot + B_Energy_Tot)/Etotal) + ' % of ' + FloatToStrf(Etotal,ffExponent,5,2));
+ WriteLn(myFile2, FloatToStr(100*Accel/ExpectedAccel));
+
+ if GridWidth < GRID_LIMIT then begin
+ New_GridWidth:=GridWidth + 1;
+ New_GridHeight:=GridHeight + 1;
+ New_GridDepth:=GridDepth + 1;
+ DoUpdate:=true;
+ Restart:=true;
+
+ // PercentBetweenParticles:=80;
+ // DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+ end
+ else begin
+ // Close the file
+ CloseFile(myFile);
+ CloseFile(myFile2);
+
+ New_GridWidth:=100;
+ New_GridHeight:=100;
+ New_GridDepth:=100;
+ DoUpdate:=true;
+ Restart:=true;
+
+ if StartOption < 3 then begin
+ New_StartOption:=StartOption + 1;
+ end
+ else begin
+ New_StartOption:=1;
+ ProfileCancel();
+ end;
+ end;
+ end;
+ end;
+
+ if two_particle_accel_dist_profile then begin
+ if profile_changed then begin
+ // Try to open the Analysis.txt file for writing to
+ AssignFile(myFile, 'AccelDistProfile_' + IntToStr(GridWidth) + '_' + FloatToStrf(ActualWidth,ffExponent,5,2) + 'm_' + IntToStr(StartOption) + '.txt');
+ ReWrite(myFile);
+ AssignFile(myFile2, 'AccelDistProfile_Summary_' + IntToStr(GridWidth) + '_' + FloatToStrf(ActualWidth,ffExponent,5,2) + 'm_' + IntToStr(StartOption) + '.txt');
+ ReWrite(myFile2);
+
+ PercentBetweenParticles:=1;
+ DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+
+// New_GridWidth:=150;
+// New_GridHeight:=150;
+// New_GridDepth:=150;
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ WriteLn(myFile, 'Grid size ' + IntToStr(GridWidth) + ', (' + FloatToStrf(PercentBetweenParticles,ffFixed,4,2) + '%) : Accel is ' + FloatToStr(Accel) + ' (' + FloatToStr(100*Accel/ExpectedAccel) + '% of expected accel ' + FloatToStr(ExpectedAccel) + ')');
+ WriteLn(myFile, 'E Energy = ' + FloatToStrf(E_Energy_Tot,ffExponent,5,2) + ', B Energy = ' + FloatToStrf(B_Energy_Tot,ffExponent,5,2) + ', Energy Total = ' + FloatToStrf((E_Energy_Tot + B_Energy_Tot),ffExponent,5,2) + ' : ' + FloatToStr(100*(E_Energy_Tot + B_Energy_Tot)/Etotal) + ' % of ' + FloatToStrf(Etotal,ffExponent,5,2));
+ WriteLn(myFile2, FloatToStr(100*Accel/ExpectedAccel));
+
+ if PercentBetweenParticles < 100 then begin
+ PercentBetweenParticles:= PercentBetweenParticles + 1;
+ DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ // Close the file
+ CloseFile(myFile);
+ CloseFile(myFile2);
+
+ New_GridWidth:=100;
+ New_GridHeight:=100;
+ New_GridDepth:=100;
+ DoUpdate:=true;
+ Restart:=true;
+
+ New_StartOption:=1;
+ ProfileCancel();
+ end;
+ end;
+ end;
+
+ if two_particle_accel_actual_width_profile then begin
+ if profile_changed then begin
+ // Try to open the Analysis.txt file for writing to
+ AssignFile(myFile, 'AccelActualWidthProfile_90_270_80.00%_16.67%_' + IntToStr(StartOption) + '.txt');
+ AssignFile(myFile2, 'AccelActualWidthProfile_Summary_90_270_80.00%_16.67%_' + '%_' + IntToStr(StartOption) + '.txt');
+
+ ReWrite(myFile);
+ ReWrite(myFile2);
+
+ ActualGridWidth.Text:=FloatToStrf(2.0E-11,ffExponent,5,2); {display actual size in metres that grid represents}
+ ProcSetGridGlobals(Self);
+
+ New_GridWidth:=90;
+ New_GridHeight:=90;
+ New_GridDepth:=90;
+
+ PercentBetweenParticles:=80;
+ DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ WriteLn(myFile, 'Actual width ' + ActualGridWidth.Text + ' Grid size ' + IntToStr(GridWidth) + ', (' + FloatToStrf(PercentBetweenParticles,ffFixed,4,2) + '%) : Accel is ' + FloatToStr(Accel) + ' (' + FloatToStr(100*Accel/ExpectedAccel) + '% of expected accel ' + FloatToStr(ExpectedAccel) + ')');
+ WriteLn(myFile, 'E Energy = ' + FloatToStrf(E_Energy_Tot,ffExponent,5,2) + ', B Energy = ' + FloatToStrf(B_Energy_Tot,ffExponent,5,2) + ', Energy Total = ' + FloatToStrf((E_Energy_Tot + B_Energy_Tot),ffExponent,5,2) + ' : ' + FloatToStr(100*(E_Energy_Tot + B_Energy_Tot)/Etotal) + ' % of ' + FloatToStrf(Etotal,ffExponent,5,2));
+ WriteLn(myFile2, FloatToStr(100*Accel/ExpectedAccel));
+
+ if ActualWidth < 6E-11 then begin
+ ActualWidth:=ActualWidth + 0.1E-11;
+ ActualGridWidth.Text:=FloatToStrf(ActualWidth,ffExponent,5,2); {display actual size in metres that grid represents}
+ ProcSetGridGlobals(Self);
+
+ New_GridWidth:=Round(90*ActualWidth/2.0E-11);
+ New_GridHeight:=Round(90*ActualWidth/2.0E-11);
+ New_GridDepth:=Round(90*ActualWidth/2.0E-11);
+
+ PercentBetweenParticles:=Round(80/(ActualWidth/2.0E-11));
+ DistBetween.Text:=FloatToStrf(PercentBetweenParticles,ffFixed,4,2);
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ // Close the file
+ CloseFile(myFile);
+ CloseFile(myFile2);
+
+ New_GridWidth:=100;
+ New_GridHeight:=100;
+ New_GridDepth:=100;
+ DoUpdate:=true;
+ Restart:=true;
+
+ New_StartOption:=1;
+ ProfileCancel();
+ end;
+ end;
+ end;
+
+ profile_changed:=false;
+
+ if two_particle_analysis then begin
+ if IterationCount >= 50 then begin
+ // Close the file
+ CloseFile(myFile);
+ if StartOption < 17 then begin
+ New_StartOption:=StartOption + 1;
+ DoUpdate:=true;
+ Restart:=true;
+ end
+ else begin
+ // Try to open the Analysis.txt file for writing to
+ AssignFile(myFile, 'AnalysisSummary.txt');
+ ReWrite(myFile);
+ AnalysisWriteHeader();
+ for StartOption:=3 to 17 do begin
+ WriteLn(myFile, 'StartOption: ' + IntToStr(StartOption) + ' Timestep: ' + IntToStr(IterationCount-1));
+ WriteLn(myFile, '');
+ AnalysisWriteResults(StartOption, IterationCount-1);
+ end;
+ // Close the file
+ CloseFile(myFile);
+ two_particle_analysis:=false;
+ CheckBox12.Checked:=false;
+ end;
+ end;
+ end;
+ end
+ else begin
+ Energy3.Text:=FloatToStr(E_Energy_Tot+B_Energy_Tot); {display total field energy}
+ end;
+
+ progress:=100;
+ update_progress_bar(progress);
+end;
+
+procedure TForm1.ProfileCancel;
+begin
+ Profile_RadioButton_Off.Checked:=true;
+ Profile_RadioButton_ActualSize.Checked:=false;
+ Profile_RadioButton_Distance.Checked:=false;
+ Profile_RadioButton_GridSize.Checked:=false;
+
+ two_particle_accel_profile_done:=true;
+ two_particle_accel_actual_width_profile:=false;
+ two_particle_accel_dist_profile:=false;
+ two_particle_accel_profile:=false;
+
+ profile_changed:=true;
+ Restart:=true;
+end;
+
+procedure TForm1.Profile_RadioButton_ActualSizeClick(Sender: TObject);
+begin
+ Profile_RadioButton_Off.Checked:=false;
+ Profile_RadioButton_ActualSize.Checked:=true;
+ Profile_RadioButton_Distance.Checked:=false;
+ Profile_RadioButton_GridSize.Checked:=false;
+
+ two_particle_accel_profile_done:=false;
+ two_particle_accel_actual_width_profile:=true;
+ two_particle_accel_dist_profile:=false;
+ two_particle_accel_profile:=false;
+ profile_changed:=true;
+ Restart:=true;
+end;
+
+procedure TForm1.Profile_RadioButton_DistanceClick(Sender: TObject);
+begin
+ Profile_RadioButton_Off.Checked:=false;
+ Profile_RadioButton_ActualSize.Checked:=false;
+ Profile_RadioButton_Distance.Checked:=true;
+ Profile_RadioButton_GridSize.Checked:=false;
+
+ two_particle_accel_profile_done:=false;
+ two_particle_accel_actual_width_profile:=false;
+ two_particle_accel_dist_profile:=true;
+ two_particle_accel_profile:=false;
+ profile_changed:=true;
+ Restart:=true;
+end;
+
+procedure TForm1.Profile_RadioButton_GridSizeClick(Sender: TObject);
+begin
+ Profile_RadioButton_Off.Checked:=false;
+ Profile_RadioButton_ActualSize.Checked:=false;
+ Profile_RadioButton_Distance.Checked:=false;
+ Profile_RadioButton_GridSize.Checked:=true;
+
+ two_particle_accel_profile_done:=false;
+ two_particle_accel_actual_width_profile:=false;
+ two_particle_accel_dist_profile:=false;
+ two_particle_accel_profile:=true;
+ profile_changed:=true;
+ Restart:=true;
+end;
+
+procedure TForm1.Profile_RadioButton_OffClick(Sender: TObject);
+begin
+ ProfileCancel();
+end;
+
+procedure TForm1.Propagate;
+begin
+ repeat
+
+ Application.ProcessMessages;
+
+ if justRestored then begin
+ New_StartOption := StartOption;
+ Restart:=false;
+ Initialise(False);
+ justRestored := false;
+ end;
+
+ if (New_StartOption<>StartOption) then StartOptionChanged:=true
+ else StartOptionChanged:=false;
+
+ if (New_StartOption<>StartOption) or Restart then begin {Restart with new start option}
+ Restart:=false;
+ Time:=0;
+ StartOption:=New_StartOption;
+
+ if (StartOption >= 3) and (StartOption <= 20) then begin
+// EnergyCorrection:=true;
+// EnergyCorrectionCheckBox.Checked:=true;
+ Profile_GroupBox.Enabled:=true;
+ Profile_RadioButton_Off.Enabled:=true;
+ Profile_RadioButton_GridSize.Enabled:=true;
+ Profile_RadioButton_Distance.Enabled:=true;
+ Profile_RadioButton_ActualSize.Enabled:=true;
+ end
+ else begin
+// EnergyCorrection:=false;
+// EnergyCorrectionCheckBox.Checked:=false;
+ Profile_GroupBox.Enabled:=false;
+ Profile_RadioButton_Off.Enabled:=false;
+ Profile_RadioButton_GridSize.Enabled:=false;
+ Profile_RadioButton_Distance.Enabled:=false;
+ Profile_RadioButton_ActualSize.Enabled:=false;
+ end;
+
+ Initialise(False);
+ UpdateDetails; {ensure the screen is displaying up-to-date info}
+ Auto_Scale(Screen); {determine the scaling factor required for current data}
+ UpdateDetails; {ensure the screen is displaying up-to-date info}
+ UpdateBitmap(Screen); {Redraw the new data on the current screen(bitmap)}
+ DisplayScreen(Screen); {Display the current screen}
+ end;
+
+ if DoUpdate then begin
+ ReDraw:=false; {Prevent re-draw unless specifically asked to}
+ UpdateDetails; {ensure the screen is displaying up-to-date info}
+
+ if (not FreezeTime) or Flip_YZ then begin {if time is running}
+ {Analyse the current grid & recalculate the new}
+ {values for the E & H fields for the TimeStep}
+ RecalcFields(Screen);
+
+ if Screen=0 then Screen:=1 else Screen:=0; {initiate screen swap}
+ ReDraw:=true;
+ end;
+
+ {Update which Field is being shown}
+ if DisplayField<>New_DisplayField then begin
+ DisplayField:=New_DisplayField;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ UpdateDetails; {ensure the screen is displaying up-to-date info}
+ Auto_Scale(Screen); {determine the scaling factor required for current data}
+ UpdateDetails; {ensure the screen is displaying up-to-date info}
+
+ if ( Form1.Timesteps.Value <> 0 ) then begin
+ if Redraw and (Timestep_count mod Form1.Timesteps.Value = 0) then begin
+ UpdateBitmap(Screen); {Redraw the new data on the current screen(bitmap)}
+ DisplayScreen(Screen); {Display the current screen}
+ Timestep_count:=0;
+ end;
+ end;
+
+ DoUpdate:=false;
+ end;
+
+ if (not FreezeTime) and (StartOption<>0) and (not Flip_YZ) and ( not AllFields or ( AllFields and (DisplayField >= POWER_FLOW_FIELD))) then begin
+ Time:=Time+TimeStep; {if time is running, increase it by TimeStep}
+ Inc(Timestep_count);
+ Inc(FrameCount);
+ DoUpdate:=true;
+ ReDraw:=true;
+ end;
+
+ Flip_YZ:=false;
+
+ if ( AllFields ) then begin
+ New_DisplayField := DisplayField + 1;
+ if( New_DisplayField > CHARGE_DENSITY_FIELD ) then New_DisplayField := 1;
+
+ DoUpdate:=true;
+ end;
+
+
+ until Quit;
+ Application.Terminate;
+end;
+
+procedure TForm1.UpdateBitmap(scr:smallint);
+{Starting with a new, black, 24bit Colour bitmap, this routine takes all the }
+{relevent selected display options into account and produces a complete bitmap}
+{image ready to be displayed to screen. The main display options it considers }
+{are: (a)which field to display. (b)Colour or Greyscale. (c)Vector arrows on/off.}
+{(d)Z Plane tiling on/off. (e)Colours for each axis.}
+var
+ colour : longint;
+ i,j,k,count :smallint;
+ xyzcol: byte;
+ value : double;
+ VectorType : boolean;
+ ArrowsX,ArrowsY,OffsetX,OffsetY: smallint;
+ ArrowsOn,FirstY: boolean;
+ ThisBitmap: Tbitmap;
+ ActualX,ActualY: smallint;
+ pointX,pointY,Xfrac,Yfrac: extended;
+ Xleft,Ytop,imax,jmax,linescan: smallint;
+ v1,v2,v3,v4,ArrowVect,ColVect,vect: vector;
+ p1,p2,p3,p4: point;
+ Xstep,Ystep,step_int: smallint;
+ GridX,GridY: extended;
+ JpegImage: TJpegImage;
+ OutStream: TFileStream;
+ path,fname,zstr: string;
+ Point1,Point2,CopyPoint1,CopyPoint2: Point;
+ xpos,ypos,zpos : smallint;
+ pixel_count,black_count: longint;
+ is_black: boolean;
+ black_thres: longint;
+
+begin
+
+ black_thres:=80;
+ black_count:=0;
+ pixel_count:=0;
+
+ if scr=0 then begin {get a new bitmap}
+ NewBitmap(@Bitmap1);
+ ThisBitmap:=Bitmap1;
+ end
+ else begin
+ NewBitmap(@Bitmap2);
+ ThisBitmap:=Bitmap2;
+ end;
+
+ if TileZ then begin
+ Xstep:=1;{round2(1/(TileScaleX*ScrScaleX))-1; {Don't bother with points which map to}
+ Ystep:=1; {round2(1/(TileScaleY*ScrScaleY))-1; {the same screen pixel}
+ end {needs to be one less than theory to prevent beat freq}
+ else begin
+ Xstep:=1; {Full size picture so use every point}
+ Ystep:=1;
+ end;
+
+ if (TileZ or (save_frames and save_3D)) then k:=0 else k:=Z_Plane; {set Z axis position. If Z Plane tiling,}
+repeat
+
+ Application.ProcessMessages;
+
+ if ( save_frames and save_3D ) then begin
+ if scr=0 then begin {get a new bitmap}
+ if (k = Z_Plane) then begin
+ NewBitmap(@Bitmap1);
+ ThisBitmap:=Bitmap1;
+ end
+ else begin
+ NewBitmap(@Bitmap2);
+ ThisBitmap:=Bitmap2;
+ end;
+ end
+ else begin
+ if (k = Z_Plane) then begin
+ NewBitmap(@Bitmap2);
+ ThisBitmap:=Bitmap2;
+ end
+ else begin
+ NewBitmap(@Bitmap1);
+ ThisBitmap:=Bitmap1;
+ end;
+ end;
+ end;
+
+ repeat {all Z values are drawn, one at a time }
+ VectorType:=false; {initialize working variables}
+ vect:=NullVect;
+ ColVect:=NullVect;
+ value:=0;
+ OffsetX:=0;
+ OffsetY:=0;
+ colour:=0;
+
+ for j:=0 to BitmapY-1 do {build array of bitmap line pointers}
+ YLinePtrs[j]:=ThisBitmap.ScanLine[j];
+ IsGrey:=not ShowColour; {set local boolean values}
+ ArrowsOn:=Arrows and (VectorX.Checked or VectorY.checked or VectorZ.checked);
+ if (not TileZ) and ArrowsOn then begin {if vector arrows are required, do some calculations}
+ arrow_step:=VectSpacing; {using spacing value from control on Form}
+ GridX:=(GridWidth+1)*ScrScaleX; {width of active region in pixels}
+ GridY:=(GridHeight+1)*ScrScaleY; {height of active region in pixels}
+
+ if Spacing_Metres.Checked then {if spacing defined as 'n' per meter}
+ arrow_step:=(GridX/(GridWidth*dx))/arrow_step; {rescale the step value}
+
+ ArrowsX:=Trunc(GridX/arrow_step); {determine number of arrows across screen}
+ ArrowsY:=Trunc(GridY/arrow_step); {determine number of arrows up/down screen}
+ OffsetX:=round2(Frac(GridX/arrow_step)*arrow_step/2); {calc offsets for 1st arrow}
+ OffsetY:=round2(Frac(GridY/arrow_step)*arrow_step/2);
+ step_int:=Round2(arrow_step);
+ if step_int=0 then Inc(step_int);
+ end
+ else step_int:=1; {prevent compiler giving 'uninitialised' warning message}
+
+ i:=0;
+
+ scr:=0;
+
+ repeat {scan through each (x,y) in Z plane of grid}
+ j:=0;
+ with points[scr]^[i,j,k] do repeat
+ vect:=VectorProperty(DisplayField,points[scr]^[i,j,k]);
+
+ case DisplayField of {depending on which field is required to display}
+ PSI_VECTOR_FIELD,
+ ELECTRIC_FIELD,
+ MAGNETIC_FIELD,
+ POWER_FLOW_FIELD,
+ HERTZIAN_FIELD,
+ VECTOR_POTENTIAL_FIELD,
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PSI_CURL_VECTOR_FIELD,
+ PARTICLE_POS_REFLECTED_FIELD,
+ PARTICLE_NEG_REFLECTED_FIELD: begin {Show Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$ELSE}
+ PSI_CURL_VECTOR_FIELD: begin {Show Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$IFEND}
+ VectorType:=true;
+ end;
+ E_ELECTRIC_FIELD: value:=E_Energy(vect); {Show energy in Electric Field}
+ E_MAGNETIC_FIELD: value:=B_Energy(vect); {Show energy in Magnetic Field}
+ PSI_SCALAR_FIELD: value:=points[scr]^[i,j,k].Psi;
+ ELECTRIC_POTENTIAL_FIELD: value:=points[scr]^[i,j,k].ElectricPotential;
+ CHARGE_DENSITY_FIELD: value:=points[scr]^[i,j,k].ChargeDensity;
+ end;
+
+ if VectorType then begin {convert component values to colour values}
+ ColVect:=VectToColours(vect,Amplification);
+ with ColVect do begin {Combine colours}
+
+ colour:=0;
+ is_black:=true;
+
+ if ( X_RGB = GREY ) then begin
+ xyzcol:=ColourRange(x/3,Amplification); {set equal RGB colour values}
+ colour:=colour + xyzcol*RED+xyzcol*GREEN+xyzcol*BLUE; {Combine colours}
+ if xyzcol >= black_thres then
+ is_black:=false;
+ end else begin
+ colour:=colour + Round2(abs(x))*X_RGB;
+ if Round2(abs(x)) >= black_thres then
+ is_black:=false;
+ end;
+
+ if ( Y_RGB = GREY ) then begin
+ xyzcol:=ColourRange(y/3,Amplification); {set equal RGB colour values}
+ colour:=colour + xyzcol*RED+xyzcol*GREEN+xyzcol*BLUE; {Combine colours}
+ if xyzcol >= black_thres then
+ is_black:=false;
+ end else begin
+ colour:=colour + Round2(abs(y))*Y_RGB;
+ if Round2(abs(y)) >= black_thres then
+ is_black:=false;
+ end;
+
+ if ( Z_RGB = GREY ) then begin
+ xyzcol:=ColourRange(z/3,Amplification); {set equal RGB colour values}
+ colour:=colour + xyzcol*RED+xyzcol*GREEN+xyzcol*BLUE; {Combine colours}
+ if xyzcol >= black_thres then
+ is_black:=false;
+ end else begin
+ colour:=colour + Round2(abs(z))*Z_RGB;
+ if Round2(abs(z)) >= black_thres then
+ is_black:=false;
+ end;
+
+ SignArray[i,j,0]:=Sign(x);
+ SignArray[i,j,1]:=Sign(y);
+ SignArray[i,j,2]:=Sign(z);
+ end;
+ end;
+ if (not VectorType) or IsGrey then begin {if greyscale display required}
+ if VectorType then value:=VectSize(vect); {if vector use vector's size}
+ xyzcol:=ColourRange(value,Amplification); {set equal RGB colour values}
+ colour:=xyzcol*RED+xyzcol*GREEN+xyzcol*BLUE; {Combine colours}
+ SignArray[i,j,0]:=Sign(xyzcol);
+ SignArray[i,j,1]:=Sign(xyzcol);
+ SignArray[i,j,2]:=Sign(xyzcol);
+ is_black:=false;
+ if xyzcol < black_thres then
+ is_black:=true;
+ end;
+ if Rendered then begin {if colour or grey rendered display req'd}
+ ColourArray[i,j]:=colour; {save point's colour in array}
+ Inc(pixel_count,1);
+ if is_black then
+ Inc(black_count,1);
+ end;
+ Inc(j,Ystep);
+ until j>GridHeight-1;
+ Inc(i,Xstep);
+ until i>GridWidth-1;
+
+ if pixel_count = 0 then
+ Inc(pixel_count);
+
+ ZplanePos:=k; {set global variable for current Z plane used by PlotPoint}
+
+ i:=0;
+ if Rendered then {if colour or greyscale Rendered display req'd}
+ repeat
+ j:=0;
+ repeat
+ PlotPoint(ThisBitmap,i,j); {plot each point onto bitmap}
+ Inc(j,Ystep);
+ until j>GridHeight-1;
+ Inc(i,Xstep);
+ until i>Gridwidth-1;
+
+ if TileZ then {if Z Plane tiling required}
+ TileCursor(ThisBitmap,ZplanePos,clGray);
+
+ if VectorType and ArrowsOn and (not TileZ) then begin {if Vector arrows required}
+
+ if Spacing_gridpoints.Checked then begin
+
+ if ( ScrScaleX > ScrScaleY ) then arrow_step:=VectSpacing*ScrScaleY;
+ if ( ScrScaleY >= ScrScaleX ) then arrow_step:=VectSpacing*ScrScaleX;
+
+ ArrowScale:=ArrowScaleFactor*arrow_step/$FF; {set scaling factor for arrow size}
+
+ i:=0;
+ repeat
+ j:=0;
+ repeat
+ ActualX:=round2(GetRealX((i+0.5))); {the actual screen x location (on the image control)}
+ ActualY:=round2(GetRealY((j+0.5))); {the actual screen y location (on the image control)}
+ p1:=points[scr]^[i,j,k];
+ ArrowVect:=VectorProperty(DisplayField,p1);
+ with ArrowVect do begin
+ x:=x*ReScaleFactor*ArrowScale; {re-scale raw values}
+ y:=y*ReScaleFactor*ArrowScale;
+ z:=z*ReScaleFactor*ArrowScale;
+ end;
+ DrawArrow(ThisBitmap,ActualX,ActualY,ArrowVect); {draw the vector arrow}
+ Inc(j,VectSpacing);
+ until j>GridHeight-1;
+ Inc(i,VectSpacing);
+ until i>Gridwidth-1;
+
+ end
+ else begin
+
+ ArrowScale:=ArrowScaleFactor*arrow_step/$FF; {set scaling factor for arrow size}
+
+ i:=OriginX+OffsetX; {calc screen x coord of arrow start}
+ imax:=round2(OriginX+GridWidth*ScrScaleX); {calculate screen coords}
+ jmax:=round2(OriginY+GridHeight*ScrScaleY); {of edge of active region}
+ repeat
+ pointX:=(i-OriginX)/ScrScaleX; {calc grid x coord for screen (i,j) }
+ Xleft:=Trunc(pointX); {find x coord of top left point}
+ Xfrac:=pointX-Xleft; {calc fractional distance to next point}
+ j:=OriginY+OffsetY; {calc screen y coord of arrow start}
+ repeat
+ pointY:=(j-OriginY)/ScrScaleY; {calc grid y coord for screen (i,j) }
+ Ytop:=Trunc(pointY); {find y coord of top left point}
+ Yfrac:=pointY-Ytop; {calc fractional distance to next point}
+ p1:=points[scr]^[Xleft,Ytop,k];
+ if Xleft<(GridWidth-1) then {get relevant point vectors}
+ p2:=points[scr]^[Xleft+1,Ytop,k] else p2:=NullPoint;
+ if YTop<(GridHeight-1) then
+ p3:=points[scr]^[Xleft,Ytop+1,k] else p3:=NullPoint;
+ if (Xleft<(GridWidth-1)) and (YTop<(GridHeight-1)) then
+ p4:=points[scr]^[Xleft+1,Ytop+1,k] else p4:=NullPoint;
+ if not PointNull(p1, DisplayField) then
+ v1:=VectorProperty(DisplayField,p1) else v1:=NullVect;
+ if not PointNull(p2, DisplayField) then
+ v2:=VectorProperty(DisplayField,p2) else v2:=NullVect;
+ if not PointNull(p3, DisplayField) then
+ v3:=VectorProperty(DisplayField,p3) else v3:=NullVect;
+ if not PointNull(p4, DisplayField) then
+ v4:=VectorProperty(DisplayField,p4) else v4:=NullVect;
+ ArrowVect:=VectorInterpolate(v1,v2,v3,v4,Xfrac,Yfrac);
+ with ArrowVect do begin
+ x:=x*ReScaleFactor*ArrowScale; {re-scale raw values}
+ y:=y*ReScaleFactor*ArrowScale;
+ z:=z*ReScaleFactor*ArrowScale;
+ end;
+ DrawArrow(ThisBitmap,i,j,ArrowVect); {draw the vector arrow}
+ Inc(j,step_int);
+ until j>=jmax; {do next arrow till done}
+ Inc(i,step_int);
+ until i>=imax;
+ end;
+ end;
+ Inc(k); {do next Z Plane}
+ until (not TileZ) or (k>GridDepth-1); {only repeat if tiling req'd and Z plane in range}
+
+ if TileZ then {draw a red rectangle around the currently selected Z plane}
+ TileCursor(ThisBitmap,Z_Plane,clRed);
+
+ if MaintainAspect and (not TileZ) then with ThisBitmap.Canvas do begin
+ Pen.Width:=1; {set pen to thin white line}
+ Pen.Style:=psSolid;
+ Pen.Color:=clGray;
+ if OriginX<>0 then begin {Draw boundary lines for Grid within the }
+ MoveTo(OriginX-2,0); {Screen space if the Aspect ratio is being}
+ LineTo(OriginX-2,BitmapY); {preserved and onlypart of the screen space}
+ MoveTo(BitmapX-OriginX,0); {is active.}
+ LineTo(BitmapX-OriginX,BitmapY);
+ end;
+ if OriginY<>0 then begin
+ MoveTo(0,OriginY-2);
+ LineTo(BitmapX,OriginY-2);
+ MoveTo(0,BitmapY-OriginY);
+ LineTo(BitmapX,BitmapY-OriginY);
+ end;
+ end;
+
+ if ( save_frames ) then begin
+ // convert to jpeg and save
+ try
+ JpegImage := TJpegImage.Create;
+ JpegImage.Assign(ThisBitmap);
+
+ path := '.\Frames\';
+
+ case DisplayField of {depending on which field is required to display}
+ PSI_VECTOR_FIELD:
+ fname := 'PsiVectWaveEqn';
+ PSI_SCALAR_FIELD:
+ fname := 'PsiWaveEqnScalar';
+ ELECTRIC_POTENTIAL_FIELD:
+ fname := 'ElecPotential';
+ HERTZIAN_FIELD:
+ fname := 'HertzianVect';
+ VECTOR_POTENTIAL_FIELD:
+ fname := 'VectPotential';
+ ELECTRIC_FIELD:
+ fname := 'Electric';
+ MAGNETIC_FIELD:
+ fname := 'Magnetic';
+ E_ELECTRIC_FIELD:
+ fname := 'E_Energy';
+ E_MAGNETIC_FIELD:
+ fname := 'B_Energy';
+ POWER_FLOW_FIELD:
+ fname := 'Power';
+ CHARGE_DENSITY_FIELD:
+ fname := 'ChargeDensity';
+ PSI_CURL_VECTOR_FIELD:
+ fname := 'PsiCurl';
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PARTICLE_POS_REFLECTED_FIELD:
+ fname := 'Particle_pos_Reflected';
+ PARTICLE_NEG_REFLECTED_FIELD:
+ fname := 'Particle_neg_Reflected';
+{$IFEND}
+ end;
+
+ if (FrameCount < 10) then fname:=fname+'00000'
+ else if (FrameCount < 100) then fname:=fname+'0000'
+ else if (FrameCount < 1000) then fname:=fname+'000'
+ else if (FrameCount < 10000) then fname:=fname+'00'
+ else if (FrameCount < 100000) then fname:=fname+'0';
+
+ if (k < 10) then zstr:='00000'
+ else if (k < 100) then zstr:='0000'
+ else if (k < 1000) then zstr:='000'
+ else if (k < 10000) then zstr:='00'
+ else zstr:='0';
+
+ if not DirectoryExists(path) then CreateDir(path);
+
+ if ( save_3D ) then begin
+ OutStream := TFileStream.Create(path+fname+IntToStr(FrameCount)+'_z'+zstr+IntToStr(k)+'.jpg',fmOpenWrite or fmCreate or fmShareDenyNone);
+ end
+ else begin
+ OutStream := TFileStream.Create(path+fname+IntToStr(FrameCount)+'.jpg',fmOpenWrite or fmCreate);
+ end;
+
+ JpegImage.SaveToStream(OutStream);
+ finally
+ JpegImage.Free;
+ OutStream.Free;
+ OutStream:=nil;
+ end;
+ end;
+
+until (not (save_frames and save_3D)) or (k>GridDepth-1); {only repeat if tiling req'd and Z plane in range}
+
+ if (AutoScale=CONTINUAL) or (AutoScale=AVERAGE) then begin
+ if (black_count/pixel_count) > 0.6 then begin
+ if DisplayLevel.Position > 0 then
+ DisplayLevel.Position:=2000 - ((2000 - DisplayLevel.Position)*2);
+ New_DisplayLevel:=DisplayLevel.Position;
+ DoUpdate:=true;
+ end;
+ end;
+
+end;
+
+procedure TForm1.DisplayScreen(scr:smallint); {display the current bitmap}
+begin
+ if scr=0 then
+ CurrentBitmap:= Bitmap1 {set the picture control to display bitmap1}
+ else
+ CurrentBitmap:= Bitmap2; {set the picture control to display bitmap2}
+ Image1.Picture.Graphic:=CurrentBitmap
+end;
+
+procedure TForm1.DistBetweenChange(Sender: TObject);
+var
+ newPercentage: extended;
+begin
+ newPercentage:=strtofloat(DistBetween.Text);
+ newPercentage:=Round(newPercentage*100)/100;
+
+ if (PercentBetweenParticles <> newPercentage) then begin
+ DoUpdate:=true;
+ Restart:=true;
+ end;
+// if not DoUpdate then ProfileCancel();
+end;
+
+procedure TForm1.Start1Click(Sender: TObject);
+{The 1st Start option has been selected}
+begin
+ New_StartOption:=1;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start2Click(Sender: TObject);
+{The 2nd Start option has been selected}
+begin
+ New_StartOption:=2;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.start3Click(Sender: TObject);
+{The 3rd Start option has been selected}
+begin
+ New_StartOption:=3;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start4Click(Sender: TObject);
+{The 4th Start option has been selected}
+begin
+ New_StartOption:=4;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start5Click(Sender: TObject);
+{The 5th Start option has been selected}
+begin
+ New_StartOption:=5;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start6Click(Sender: TObject);
+{The 6th Start option has been selected}
+begin
+ New_StartOption:=6;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start7Click(Sender: TObject);
+{The 7th Start option has been selected}
+begin
+ New_StartOption:=7;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start8Click(Sender: TObject);
+{The 8th Start option has been selected}
+begin
+ New_StartOption:=8;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start9Click(Sender: TObject);
+{The 9th Start option has been selected}
+begin
+ New_StartOption:=9;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start10Click(Sender: TObject);
+{The 10th Start option has been selected}
+begin
+ New_StartOption:=10;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start11Click(Sender: TObject);
+{The 11th Start option has been selected}
+begin
+ New_StartOption:=11;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start12Click(Sender: TObject);
+{The 12th Start option has been selected}
+begin
+ New_StartOption:=12;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start13Click(Sender: TObject);
+{The 13th Start option has been selected}
+begin
+ New_StartOption:=13;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start14Click(Sender: TObject);
+{The 14th Start option has been selected}
+begin
+ New_StartOption:=14;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start15Click(Sender: TObject);
+{The 15th Start option has been selected}
+begin
+ New_StartOption:=15;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start16Click(Sender: TObject);
+{The 16th Start option has been selected}
+begin
+ New_StartOption:=16;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start17Click(Sender: TObject);
+{The 17th Start option has been selected}
+begin
+ New_StartOption:=17;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start18Click(Sender: TObject);
+{The 18th Start option has been selected}
+begin
+ New_StartOption:=18;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start19Click(Sender: TObject);
+{The 19th Start option has been selected}
+begin
+ New_StartOption:=19;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start20Click(Sender: TObject);
+{The 20th Start option has been selected}
+begin
+ New_StartOption:=20;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start21Click(Sender: TObject);
+{The 21st Start option has been selected}
+begin
+ New_StartOption:=21;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start22Click(Sender: TObject);
+{The 22nd Start option has been selected}
+begin
+ New_StartOption:=22;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start23Click(Sender: TObject);
+{The 23rd Start option has been selected}
+begin
+ New_StartOption:=23;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start24Click(Sender: TObject);
+{The 24th Start option has been selected}
+begin
+ New_StartOption:=24;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start25Click(Sender: TObject);
+{The 25th Start option has been selected}
+begin
+ New_StartOption:=25;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start26Click(Sender: TObject);
+{The 26th Start option has been selected}
+begin
+ New_StartOption:=26;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start27Click(Sender: TObject);
+{The 27th Start option has been selected}
+begin
+ New_StartOption:=27;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+procedure TForm1.Start28Click(Sender: TObject);
+{The 28th Start option has been selected}
+begin
+ New_StartOption:=28;
+ if StartOption<>New_StartOption then begin
+ DoUpdate:=true;
+ Restart:=true;
+ ProfileCancel();
+ end;
+end;
+
+function TForm1.sign(number: extended): shortint;
+{This function takes a real number and returns either -1 or +1 }
+{If: number<0, -1 is returned }
+{ number>=0, +1 is returned }
+var
+ signval: shortint;
+begin
+ if number>=0 then signval:=1
+ else signval:=-1;
+ Result:=signval;
+end;
+
+procedure TForm1.Field0Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=PSI_VECTOR_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field1Click(Sender: TObject);
+{The Electric field has been selected to be displayed}
+begin
+ New_DisplayField:=PSI_CURL_VECTOR_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field2Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=ELECTRIC_POTENTIAL_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field3Click(Sender: TObject);
+{The Psi Vector field has been selected to be displayed}
+begin
+ New_DisplayField:=HERTZIAN_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field4Click(Sender: TObject);
+{The Magnetic field Energy has been selected to be displayed}
+begin
+ New_DisplayField:=VECTOR_POTENTIAL_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field5Click(Sender: TObject);
+{The Power flow field has been selected to be displayed}
+begin
+ New_DisplayField:=ELECTRIC_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field6Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=MAGNETIC_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field7Click(Sender: TObject);
+{The Electric field Energy has been selected to be displayed}
+begin
+ New_DisplayField:=E_ELECTRIC_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field8Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=E_MAGNETIC_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field9Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=POWER_FLOW_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field10Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+ New_DisplayField:=CHARGE_DENSITY_FIELD;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Field11Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ New_DisplayField:=PARTICLE_POS_REFLECTED_FIELD;
+ DoUpdate:=true;
+{$IFEND}
+end;
+
+procedure TForm1.Field12Click(Sender: TObject);
+{The Magnetic field has been selected to be displayed}
+begin
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ New_DisplayField:=PARTICLE_NEG_REFLECTED_FIELD;
+ DoUpdate:=true;
+{$IFEND}
+end;
+
+procedure TForm1.TimeFreezeClick(Sender: TObject);
+{The Freeze Time control has been changed, so toggle button's text}
+begin
+ if FreezeTime then New_FreezeTime:=false else New_FreezeTime:=true;
+ DoUpdate:=true;
+end;
+
+function TForm1.Gauss(x: extended): extended;
+{return a value (between 0 and -1) corresponding to a gaussian distribution}
+{based of the x value supplied. The whole curve (essentially) is defined }
+{between x=-2 to x=2}
+begin
+ result:=Exp(-sqr(x));
+end;
+
+procedure TForm1.UpdateDetails();
+var
+ ReCalcTileSize,ReCalcAspectRatio: boolean;
+begin
+ ReCalcTileSize:=false; {Default re-calc to Off}
+ ReCalcAspectRatio:=false; {Default re-calc to Off}
+
+ Flip_YZ:=New_Flip_YZ;
+ New_Flip_YZ:=false;
+
+ if ViewTop<>ViewFromTop.Checked then begin
+ ViewTop := ViewFromTop.Checked;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ // If flipping Y & Z planes, need to make sure they have the same dimensions first.
+ if Flip_YZ then begin
+ if GridHeight > GridDepth then New_GridHeight := GridDepth;
+ if GridDepth > GridHeight then New_GridDepth := GridHeight;
+ end;
+
+ {Reset the Grid Dimensions if required (retains existing data)}
+ if ((New_GridWidth<>GridWidth) or (New_GridHeight<>GridHeight) or
+ (New_GridDepth<>GridDepth)) or FirstPass then begin
+ ReAllocGridMemory; {Re-allocate memory for new Grid size}
+ GridWidth:=New_GridWidth; {Adopt new Dimensions}
+ GridHeight:=New_GridHeight;
+ GridDepth:=New_GridDepth;
+
+ if ( GridHeight <> GridDepth ) then ViewFromTop.Enabled := false else ViewFromTop.Enabled := true;
+
+ GridX.Text:=IntToStr(GridWidth); {Ensure Controls reflect Current}
+ GridY.Text:=IntToStr(GridHeight); {program settings.}
+ GridZ.Text:=IntToStr(GridDepth);
+ SetGridGlobals; {Re-Calc Globals for new Grid size}
+ ReCalcAspectRatio:=true; {Trigger an Aspect Ratio recalculation}
+ ReCalcTileSize:=true; {Trigger a Tile Size recalculation}
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update Time Related Displays}
+ TimeDisplay.Text:='Time (Secs) : '+FloatToStr(Time); {update time display}
+ if (FreezeTime<>New_FreezeTime) or FirstPass then begin
+ FreezeTime:=New_FreezeTime;
+ with TimeFreeze do
+ if FreezeTime then
+ Caption:='Unfreeze Time'
+ else
+ Caption:='Freeze Time';
+ end;
+
+ {Update the Auto-Scale selection}
+ if (New_AutoScale<>AutoScale) or FirstPass then begin
+ if (AutoScale=CONTINUAL) or (AutoScale=AVERAGE) then begin {Re-Enable control incase it was out of}
+ ReScale.Enabled:=true; {range whilst autoscaling.}
+ New_ReScale:=ReScaleFactor; {Prevent the next update, as the control}
+ New_DisplayLevel:=Display_Level;{was turned off.}
+ end;
+ AutoScale:=New_AutoScale; {Adopt the new control state.}
+ case AutoScale of
+ START: begin
+ if Time=0 then begin
+ AutoWarn.Top:=Auto1.Top+2; {Show Auto-scale warning indicator}
+ AutoWarn.Visible:=true; {next to the relevant button.}
+ AutoWarnTimer.Enabled:=true;
+ end
+ else begin
+ AutoWarn.Visible:=false;
+ AutoWarnTimer.Enabled:=false;
+ end;
+ end;
+ CONTINUAL: begin
+ AutoWarn.Top:=Auto2.Top+2; {Show Auto-scale warning indicator}
+ AutoWarn.Visible:=true; {next to the relevant button.}
+ AutoWarnTimer.Enabled:=true;
+ end;
+ NEVER: begin
+ AutoWarn.Visible:=false;
+ AutoWarnTimer.Enabled:=false;
+ end;
+ AVERAGE: begin
+ AutoWarn.Top:=Auto2.Top+2; {Show Auto-scale warning indicator}
+ AutoWarn.Visible:=true; {next to the relevant button.}
+ AutoWarnTimer.Enabled:=true;
+ end;
+ end;
+ end;
+
+ {Turn off Auto Scale indicator after time started if req'd}
+ if (Time<>0) and (AutoScale=START) then begin
+ AutoWarn.Visible:=false;
+ AutoWarnTimer.Enabled:=false;
+ end;
+
+ {Update the display mode Colour/GreyScale}
+ if New_ShowColour<>ShowColour then begin
+ ShowColour:=New_ShowColour;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update Axis Colour Allocation}
+ if UpdateColours or FirstPass then begin
+ UpdateAxisColours(New_AxisColours);
+ UpdateColours:=false;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ if (New_Rendered<>Rendered) or FirstPass then begin
+ Rendered:=New_Rendered;
+ if Rendered then begin
+ RendGroup.Enabled:=true;
+ RenderOption1.Enabled:=true;
+ RenderOption2.Enabled:=true;
+ RenderOption3.Enabled:=true;
+ ColourButton.Enabled:=true;
+ GreyScaleButton.Enabled:=true;
+ end
+ else begin
+ RendGroup.Enabled:=false;
+ RenderOption1.Enabled:=false;
+ RenderOption2.Enabled:=false;
+ RenderOption3.Enabled:=false;
+ ColourButton.Enabled:=false;
+ GreyScaleButton.Enabled:=false;
+ end;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update the Maintain Aspect Ratio Checkbox control}
+ if (New_MaintainAspect<>MaintainAspect) or FirstPass then begin
+ MaintainAspect:=New_MaintainAspect;
+ ReCalcAspectRatio:=true; {Trigger an Aspect Ratio recalculation}
+ ReCalcTileSize:=true; {Trigger a Tile Size recalculation}
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update the screen rendering Option}
+ if (New_Render<>Render) or FirstPass then begin
+ Render:=New_Render;
+ ReCalcTileSize:=true; {Reset Tiling size for new Rendering selection}
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update Z Tiling Option Variable and button display}
+ if (TileZ<>New_TileZ) or FirstPass then begin
+ TileZ:=New_TileZ;
+ ReDraw:=true; {Trigger a screen re-draw}
+ with Z_Tiling do
+ if TileZ then
+ Caption:='Single Z Plane'
+ else
+ Caption:='Tile Z Planes';
+ end;
+
+ {Update Currently displayed Z plane, the control's value and its display}
+ if (Z_Plane<>New_ZPlane) or FirstPass then begin
+ {Shift Tile Cursor if new tile selected}
+ if TileZ then begin
+ TileCursor(CurrentBitmap,Z_Plane,clGray); {return old Tile's border to Grey}
+ TileCursor(CurrentBitmap,New_ZPlane,clRed); {Outline new Tile's border in Red}
+ end
+ else ReDraw:=true; {Trigger a screen re-draw}
+ Z_Plane:=New_ZPlane;
+ ZPlane.Position:=Z_Plane+1;
+ Z_Plane_Number.Text:='Z Plane : '+IntToStr(Z_Plane+1)+' (of '+IntToStr(GridDepth)+')';
+ end;
+
+ if ReCalcAspectRatio then SetAspectRatio; {Re-Calc if flagged}
+ if ReCalcTileSize then SetTileSize;
+
+ {Update the Re-scaling factor value and ensure control's value agrees}
+ if (ReScaleFactor<>New_ReScale) or FirstPass then begin
+ ReScaleFactor:=New_ReScale;
+ ReScale.Enabled:=true;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {Update the DisplayLevel control's position}
+ if (Display_Level<>New_DisplayLevel) or FirstPass then begin
+ Display_Level:=New_DisplayLevel;
+ if ((AutoScale=CONTINUAL) or (AutoScale=AVERAGE) or ((AutoScale=START) and (Time=0))) then
+ DisplayLevel.Position:=Display_Level;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ if (Rate_Of_Time<>New_RateOfTime) or FirstPass then begin
+ Rate_Of_Time:=New_RateOfTime;
+ TimeStep:=(Rate_Of_Time/RATE_OF_TIME_DIVISOR)/SpeedOfLight; {Increment of Time per iteration - Secs }
+ end;
+
+ {Calc the Amplification factor & update its display}
+// CentrePos:=Round2(DisplayLevel.Max/2);
+ Amplification:=1000*(DisplayLevel.Max - Display_Level);
+ AmpDisplay.Text:='Amplification : '+IntToStr(Trunc(Amplification))+'%';
+ Amplification:=ReScaleFactor*Amplification/100;
+
+ {Update all the Field's statistical values}
+ Energy1.Text:=FloatToStr(E_Energy_Tot); {display the Electric field energy total}
+ Energy2.Text:=FloatToStr(B_Energy_Tot); {display the Magnetic field energy total}
+// Energy3.Text:=FloatToStr(E_Energy_Tot+B_Energy_Tot); {display total field energy}
+ if (ShowEnergy_CheckBox.Checked) then Energy4.Text:=FloatToStr(Etotal); {display total field energy}
+
+// ActualGridWidth.Text:=FloatToStrf(ActualWidth,ffExponent,5,2); {display actual size in metres that grid represents}
+
+ try
+ New_VectSpacing:=StrToInt(VectorSpacing.Text);
+ except {catch any invalid integer conditions}
+ on E: Exception do begin
+ VectorSpacing.Text:='11';
+ New_VectSpacing:=11;
+ end;
+ end;
+
+ {Update the Vector Arrows' spacing value}
+ if (New_VectSpacing<>VectSpacing) or FirstPass then begin
+ VectSpacing:=New_VectSpacing;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ {The X,Y or Z vector arrows have been selected/de-selected, so re-draw req'd}
+ if VectorChange then begin
+ VectorChange:=false;
+ ReDraw:=true;
+ end;
+
+ {if the Arrows separation units have been changed, trigger a re-draw}
+ if ArrowsUnitsChange then begin
+ ArrowsUnitsChange:=false;
+ ReDraw:=true;
+ end;
+
+ {Update Arrows variable & status of Vector Arrows controls}
+ if (Arrows<>New_Arrows) or FirstPass then begin
+ Arrows:=New_Arrows;
+ if Arrows then begin
+ VectorX.Enabled:=true;
+ VectorY.Enabled:=true;
+ VectorZ.Enabled:=true;
+ Spacing_Text.Enabled:=true;
+ VectorSpacing.Enabled:=true;
+ Spacing_pixels.Enabled:=true;
+ Spacing_metres.Enabled:=true;
+ Spacing_gridpoints.Enabled:=true;
+ end
+ else begin
+ VectorX.Enabled:=false;
+ VectorY.Enabled:=false;
+ VectorZ.Enabled:=false;
+ Spacing_Text.Enabled:=false;
+ VectorSpacing.Enabled:=false;
+ Spacing_pixels.Enabled:=false;
+ Spacing_metres.Enabled:=false;
+ Spacing_gridpoints.Enabled:=false;
+ end;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ if (ArrowScaleFactor <> New_ArrowScaleFactor) or FirstPass then begin
+ ArrowScaleFactor := New_ArrowScaleFactor;
+ ReDraw:=true; {Trigger a screen re-draw}
+ end;
+
+ FirstPass:=false;
+end;
+
+procedure TForm1.ZPlaneChange(Sender: TObject);
+{The Z plane control has been changed, so re-validate display values}
+begin
+ New_ZPlane:=ZPlane.Position-1;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.DisplayLevelChange(Sender: TObject);
+{The displaylevel slider control has been changed, so re-validate display values}
+begin
+ New_DisplayLevel:=DisplayLevel.Position;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.ReScaleChange(Sender: TObject);
+{The rescale factor control has been changed, so re-validate display values}
+begin
+ try
+ New_ReScale:=ReScale.value;
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ New_ReScale:=ReScaleFactor;
+ end;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.X_RedClick(Sender: TObject);
+{The x axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='X';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.X_GreenClick(Sender: TObject);
+{The x axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='X';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.X_BlueClick(Sender: TObject);
+{The x axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='X';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.X_greyClick(Sender: TObject);
+begin
+ New_AxisColours:='X';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.X_noneClick(Sender: TObject);
+begin
+ New_AxisColours:='X';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Y_RedClick(Sender: TObject);
+{The y axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Y';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Y_GreenClick(Sender: TObject);
+{The y axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Y';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Y_BlueClick(Sender: TObject);
+{The y axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Y';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Y_greyClick(Sender: TObject);
+begin
+ New_AxisColours:='Y';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Y_noneClick(Sender: TObject);
+begin
+ New_AxisColours:='Y';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Z_RedClick(Sender: TObject);
+{The z axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Z';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Z_GreenClick(Sender: TObject);
+{The z axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Z';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Z_BlueClick(Sender: TObject);
+{The z axis display colour has been changed, so set it to new colour}
+begin
+ New_AxisColours:='Z';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Z_greyClick(Sender: TObject);
+begin
+ New_AxisColours:='Z';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Z_noneClick(Sender: TObject);
+begin
+ New_AxisColours:='Z';
+ UpdateColours:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.GreyscaleButtonClick(Sender: TObject);
+{The greyscale display button has been selected, so set global variable}
+begin
+ if GreyscaleButton.Checked then
+ New_ShowColour:=false else New_ShowColour:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.ColourButtonClick(Sender: TObject);
+{The colour gradient display button has been selected, so set global variable}
+begin
+ if ColourButton.Checked then
+ New_ShowColour:=true else New_ShowColour:=false;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.UpdateAxisColours(which: string);
+{Ensures that the colour rectangles showing the primary colour currently}
+{being used to depict that axis, are correct. If ALL is passed as a parameter}
+{all the colour bitmaps are updated. Likewise if X,Y or Z are passed then only}
+{that axis colour is updated.}
+begin
+ if (which='ALL') or (which='X') then begin
+ if X_Red.Checked then X_RGB:=RED; {only one of these can be true}
+ if X_Green.Checked then X_RGB:=GREEN;
+ if X_Blue.Checked then X_RGB:=BLUE;
+ if X_grey.Checked then X_RGB:=GREY;
+ if X_none.Checked then X_RGB:=BLACK;
+ with X_Colour.Picture do
+ case X_RGB of {point to correct bitmap}
+ RED: Graphic:=BitmapRed;
+ GREEN: Graphic:=BitmapGreen;
+ BLUE: Graphic:=BitmapBlue;
+ GREY: Graphic:=BitmapGrey;
+ BLACK: Graphic:=BitmapBlack;
+ end;
+ end;
+ if (which='ALL') or (which='Y') then begin
+ if Y_Red.Checked then Y_RGB:=RED; {only one of these can be true}
+ if Y_Green.Checked then Y_RGB:=GREEN;
+ if Y_Blue.Checked then Y_RGB:=BLUE;
+ if Y_grey.Checked then Y_RGB:=GREY;
+ if Y_none.Checked then Y_RGB:=BLACK;
+ with Y_Colour.Picture do
+ case Y_RGB of {point to correct bitmap}
+ RED: Graphic:=BitmapRed;
+ GREEN: Graphic:=BitmapGreen;
+ BLUE: Graphic:=BitmapBlue;
+ GREY: Graphic:=BitmapGrey;
+ BLACK: Graphic:=BitmapBlack;
+ end;
+ end;
+ if (which='ALL') or (which='Z') then begin
+ if Z_Red.Checked then Z_RGB:=RED; {only one of these can be true}
+ if Z_Green.Checked then Z_RGB:=GREEN;
+ if Z_Blue.Checked then Z_RGB:=BLUE;
+ if Z_grey.Checked then Z_RGB:=GREY;
+ if Z_none.Checked then Z_RGB:=BLACK;
+ with Z_Colour.Picture do
+ case Z_RGB of {point to correct bitmap}
+ RED: Graphic:=BitmapRed;
+ GREEN: Graphic:=BitmapGreen;
+ BLUE: Graphic:=BitmapBlue;
+ GREY: Graphic:=BitmapGrey;
+ BLACK: Graphic:=BitmapBlack;
+ end;
+ end;
+end;
+
+procedure TForm1.Auto1Click(Sender: TObject);
+{The AutoScale at Start Only button has been selected}
+begin
+ New_AutoScale:=START;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Auto2Click(Sender: TObject);
+{The AutoScale Continual button has been selected}
+begin
+ New_AutoScale:=CONTINUAL;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Auto3Click(Sender: TObject);
+{The AutoScale Never button has been selected}
+begin
+ New_AutoScale:=NEVER;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Auto4Click(Sender: TObject);
+{The AutoScale Never button has been selected}
+begin
+ New_AutoScale:=AVERAGE;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Auto_Scale(scr: smallint); {Calculate scaling factor for data display}
+{If AutoScale is not set to NEVER, then the colours (RGB values) are scaled}
+{such that the grid point of maximum absolute value for the quantity currently}
+{being displayed is given the maximum colour value (255 or $FF). The other }
+{points are given colours determined by a linear transition from zero to that}
+{maximum value. The absolute values are used for determining the colour, so}
+{that for example: -100 and +100 will be displayed as the same colour}
+const
+ PixMax=$FF;
+begin
+ if AutoScale<> NEVER then begin {only autoscale if option selected}
+ if (AutoScale=CONTINUAL) or (AutoScale=AVERAGE) or ((AutoScale=START) and (Time=0)) then begin
+
+ if (AutoScale=AVERAGE) then
+ begin
+ FindAverageVal(scr,DisplayField); {Find the Average value of the field concerned}
+ end
+ else begin
+ FindMaxVal(scr,DisplayField); {Find the Maximum value of the field concerned}
+ end;
+
+ if MaxVal<>0 then begin
+ if not IsVectorField(DisplayField) then begin
+ New_ReScale:=(PixMax/MaxVal)/3;
+ end
+ else begin
+ New_ReScale:=PixMax/MaxVal;
+ end;
+ end
+ else begin
+ New_ReScale:=0; {if all screen points have zero value,}
+ end; {reset default scaling control positions}
+
+ DoUpdate:=true;
+ end;
+ end;
+end;
+
+procedure TForm1.MaxCheck(element: PointPtr);
+begin
+ with element.Electric do {for Electric field of current grid point}
+ if Max_E<>0 then begin {if a maximum allowable value is defined}
+ if x>Max_E then x:=Max_E; {restrict the point's values to within this}
+ if y>Max_E then y:=Max_E; {range of values}
+ if z>Max_E then z:=Max_E;
+ if x<-Max_E then x:=-Max_E;
+ if y<-Max_E then y:=-Max_E;
+ if z<-Max_E then z:=-Max_E;
+ end;
+ with element.Magnetic do {for Magnetic field of current grid point}
+ if Max_B<>0 then begin {if a maximum allowable value is defined}
+ if x>Max_B then x:=Max_B; {restrict the point's values to within this}
+ if y>Max_B then y:=Max_B; {range of values}
+ if z>Max_B then z:=Max_B;
+ if x<-Max_B then x:=-Max_B;
+ if y<-Max_B then y:=-Max_B;
+ if z<-Max_B then z:=-Max_B;
+ end;
+end;
+
+function TForm1.VectSize(vect: Vector): extended;
+{Calculate the total vector size by combining the three component vectors}
+begin
+ with vect do
+ Result:=sqrt(sqr(x)+sqr(y)+sqr(z));
+end;
+
+function TForm1.BtoH(Bvect: Vector): Vector;
+{Convert Magnetic B vector to Magnetic H vector}
+var
+ Hvect: Vector;
+begin
+
+ with Hvect do begin
+ x := Bvect.x/Permeability;
+ y := Bvect.y/Permeability;
+ z := Bvect.z/Permeability;
+ end;
+
+ Result:=Hvect;
+end;
+
+function TForm1.E_Energy(E_vect: Vector): extended;
+{ calculate the energy density in the electric field at the point with instantaneous amplitude E_amp. }
+{ }
+{ Assuming a time-harmonic electric field: }
+{ From : https://web.stanford.edu/group/fan/publication/Shin_JOSAB_29_1048_2012.pdf }
+{ and : https://doubtnut.com/question-answer-physics/the-average-value-of-electric-energy-density-in-an-electromagnetic-wave-is-e0-is-peak-value-11971302 }
+{ and : https://arxiv.org/pdf/1111.4354.pdf (p12,13) }
+{ Electric energy density ue=(1/2)*ε0*ε^2rms
+
+ RMS in 1 dimension:
+ Ems=E/√2
+ ∴ue=(1/4)*ε0*E^2
+
+ RMS in 3 cartesian coordinate dimensions (x, y, z), as the
+ wave-function is sinusoidal in all three dimensions:
+
+ Ems=E/(√2*√2*√2)
+ ∴ue=(1/16)*ε0*E^2
+}
+var
+ amp: Extended;
+begin
+ amp:= VectSize(E_vect);
+ Result:=0.5*Permittivity*sqr(amp/(sqrt(2)*sqrt(2)*sqrt(2)));
+end;
+
+function TForm1.B_Energy(B_vect: Vector): extended;
+{calculate the energy density in the magnetic field at the point with instantaneous amplitude B_amp. }
+{ }
+{ Assuming a time-harmonic electromagnetic field: }
+{ From: https://www.researchgate.net/publication/249341418_Electromagnetic_energy_density_in_dispersive_and_dissipative_media }
+{ ue=(1/4)*(ε0*E^2 + μ*H^2)
+{
+{ Magnetic energy density ue=(1/2)*μ0*H^2rms
+{
+ RMS in 1 dimension:
+ Hms=H/√2
+ ∴ue=(1/4)*μ0*H^2
+
+ RMS in 3 cartesian coordinate dimensions (x, y, z), as the
+ wave-function is sinusoidal in all three dimensions:
+
+ Hms=H/(√2*√2*√2)
+ ue=(1/16)*μ0*H^2
+}
+var
+ amp: Extended;
+begin
+ amp:= VectSize(BtoH(B_vect));
+ Result:=0.5*Permeability*sqr(amp/(sqrt(2)*sqrt(2)*sqrt(2)));
+end;
+
+function TForm1.PowerFlow(Apoint: point): vector;
+{Calculate the Power flow vector at a point in the grid by taking }
+{the vector cross product of the Electric & Magnetic fields, and }
+{dividing the result by the Permeability of free space.}
+var
+ vect: Vector;
+begin
+ with Apoint do
+ vect:=VectorCross(Electric,Magnetic);
+ with vect do begin
+ x:=x/Permeability; {Rescale values by area of grid point}
+ y:=y/Permeability;
+ z:=z/Permeability;
+ end;
+ Result:=vect;
+end;
+
+function TForm1.RMS_PowerFlow(Apoint: point): vector;
+var
+ vect: Vector;
+begin
+ // Get instantaneous Power Flow
+ vect:=PowerFlow(Apoint);
+
+ // Calculate RMS of Power Flow (effective, actual Power Flow)
+ // RMS in 3 cartesian coordinate dimensions (x, y, z), as the
+ // wave-function is sinusoidal in all three dimensions:
+ //
+ // Ems=E/(√2*√2*√2)
+ // ∴ue=(1/16)*ε0*E^2
+ //
+ // Hms=H/(√2*√2*√2)
+ // ∴ue=(1/16)*μ0*H^2
+
+ with vect do begin
+ x:=(x/16);
+ y:=(y/16);
+ z:=(z/16);
+ end;
+ Result:=vect;
+end;
+
+procedure TForm1.Vect_ArrowsClick(Sender: TObject);
+{The Vector Arrows button has been changed, so either enable or disable}
+{all the vector option controls}
+begin
+ if Vect_Arrows.Checked then
+ New_Arrows:=true
+ else
+ New_Arrows:=false;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.DrawArrow(ThisBitmap: Tbitmap;x,y: smallint;arrow: Vector);
+var {draws a vector corresponding to the relevant x,y & z values}
+ {x & y vectors are depicted as lines, z as crosses or circles}
+ xpos,ypos,zsize: smallint;
+ size: extended;
+begin
+ with ThisBitmap.Canvas do begin {using the appropriate bitmap}
+ with Pen do begin
+ Width:=1; {set pen to thin white line}
+ Color:=clWhite;
+ Style:=psSolid;
+
+ size:=VectSize(arrow);
+
+ if VectorX.Checked then begin
+ if (arrow.x > arrow_step) then begin
+ arrow.x := arrow_step*(arrow.x/size);
+ Style:=psDot;
+ end;
+
+ if (arrow.x < -arrow_step) then begin
+ arrow.x := -arrow_step*(-arrow.x/size);
+ Style:=psDot;
+ end;
+ end;
+
+ if VectorY.Checked then begin
+ if (arrow.y > arrow_step) then begin
+ arrow.y := arrow_step*(arrow.y/size);
+ Style:=psDot;
+ end;
+
+ if (arrow.y < -arrow_step) then begin
+ arrow.y := -arrow_step*(-arrow.y/size);
+ Style:=psDot;
+ end;
+ end;
+
+ if VectorZ.Checked then begin
+ if (arrow.z > arrow_step) then begin
+ arrow.z := arrow_step*(arrow.z/size);
+ Style:=psDot;
+ end;
+
+ if (arrow.z < -arrow_step) then begin
+ arrow.z := -arrow_step*(-arrow.z/size);
+ Style:=psDot;
+ end;
+ end;
+ end;
+
+ MoveTo(x,y); {start the vector from the point (x,y) }
+ if VectorX.Checked then {if x axis vectors required calc xpos}
+ xpos:=round2(x+(arrow.x))
+ else xpos:=x; {else use x value of starting point}
+ if VectorY.Checked then {if y axis vectors required calc ypos}
+ ypos:=round2(y+(arrow.y))
+ else ypos:=y; {else use y value of starting point}
+ LineTo(xpos,Ypos); {draw the vector arrow for the x and/or y displacement}
+ if VectorZ.Checked then begin {if z axis vectors required,}
+ zsize:=round2(arrow.z); {calc vector size}
+ if arrow.z>0 then begin {if z>0 (coming out of the page) draw circle of appropriate size}
+ MoveTo(x,y);
+ brush.Style:=bsClear; {ensure circle is not filled}
+ Ellipse(x-zsize,y-zsize,x+zsize,y+zsize);
+ end;
+ if arrow.z<0 then begin {if z<0 (going into the page) draw cross of appropriate size}
+ MoveTo(x-zsize,y-zsize);
+ LineTo(x+zsize-1,y+zsize-1); {slight correction added to fix arrow's}
+ MoveTo(x-zsize,y+zsize); {look - make both sides look even}
+ LineTo(x+zsize-1,y-zsize+1);
+ end;
+ end;
+ end;
+end;
+
+procedure TForm1.NewBitmap(BmapPtr: BitmapPtr);
+{given a pointer to a bitmap, erase the bitmap it points to (if any) }
+{and return the pointer pointing to a new blank 24bit bitmap with }
+{width and height the same as the Image control}
+begin
+ if BmapPtr<>nil then BmapPtr.free; {free memory of current bitmap if req'd}
+ BmapPtr^:=TBitmap.Create; {create a new bitmap}
+ if BmapPtr<> nil then with BmapPtr^ do begin {using the new bitmap's pointer}
+ Height:=Image1.Height; {set bitmap height}
+ Width:=Image1.Width; {set bitmap width}
+ Canvas.Brush.Color:=clBlack;
+ Canvas.FloodFill(1,1,clBlack,fsBorder); {ensure black filled}
+ PixelFormat:=pf24bit; {set 24bit colour}
+ end;
+end;
+
+procedure TForm1.PlotPoint(Bmap: TBitmap; x, y: smallint);
+{Using the colour array built by UpdateBitmap, display the colour information}
+{of the point (x,y) either as: (a) a extended pixel. (b) a circle of uniform }
+{colour with diametre equal to the smallest of ScrScaleX & ScrScaleY. }
+{ (c) a rectangle of width ScrScaleX and height ScrScaleY with the original }
+{colour value in the centre, and a graduated change to match the other grid }
+{points around it - the colour graduation is provided by VectorInterpolate }
+{and uses a linear interpolation in the X and Y directions for each of the }
+{three colour planes (Red Green Blue).}
+var
+ ScreenX,ScreenY: extended;
+ Edge,PointNum: byte;
+ DoQuad1,DoQuad2,DoQuad3,DoQuad4: boolean;
+ TileOfsX,TileOfsY: smallint;
+ newx,newy: smallint;
+ Signs: array[1..9,1..3] of shortint;
+ Colour: TColor;
+ XCol,Yrow: Longint;
+ Xtop,Ytop,Xbot,Ybot: extended;
+ PixelRender: smallint;
+ DrawPoint: boolean;
+begin
+ TileOfsX:=0;
+ TileOfsY:=0;
+ DrawPoint:=true;
+ PixelRender:=Render;
+ Colour:=ColourArray[x,y];
+ begin
+ if TileZ then begin {if the Z planes are required to be tiled}
+ Yrow:=ZplanePos div TileXcount;
+ Xcol:=ZplanePos mod TileXcount;
+ TileRect:=TileGrid.CellRect(Xcol,Yrow);
+ with TileRect do begin
+ TileOfsX:=Left+EdgeSize; {add a bit bypass tile's border}
+ TileOfsY:=Top+EdgeSize;
+ end;
+ TileHalfX:=TileScrScaleX/2; {calc midway points}
+ TileHalfY:=TileScrScaleY/2;
+ ScreenX:=TileOfsX+(x*TileScrScaleX)+TileHalfX; {calc x coord for pixel}
+ ScreenY:=TileOfsY+(y*TileScrScaleY)+TileHalfY; {calc y coord for pixel}
+ if ((TileScrScaleX<=1) and (TileScrScaleY<=1)) then
+ PixelRender:=OneToOne; {prevent uneccesary work}
+ { if (GridDepth>50) and (PixelRender=Blend) then PixelRender:=Chunky; }
+ {Blend takes too long if too many Z Planes}
+ if not ((ScreenX=TileRect.Right then Xbot:=TileRect.Right-1;
+ if Ytop0 then
+ Result:=round((colour and Mask)/primary) {mask out unwanted colours}
+ else
+ Result:=0;
+end;
+
+function TForm1.EdgeCase(x, y, Xmin, Ymin, Xmax, Ymax: smallint): byte;
+ {determines if the point (x,y) lies at the edge of the rectangle }
+ {defined by (Xmin,Ymin) and (Xmax,Ymax), and if so, what sort of }
+ {edge is it on (ie. left, right, bottom left corner etc...). This}
+ {information is required during calculations which require comparisons}
+ {between adjacent grid points, where such points may lie out of the }
+ {grid's bounds. The case values correspond to the following locations:}
+ { (top left) 1 2 3 }
+ { 4 5 6 }
+ { 7 8 9 (bottom right) }
+var
+ Xcase,Ecase: byte;
+begin
+ Ecase:=0;
+ if x=Xmin then Xcase:=1 {calc X coord boundary state}
+ else if x=Xmax then Xcase:=3 {1=left boundary, 3=right boundary}
+ else Xcase:=2;
+
+ if y=Ymin then {calc overall boundary state using y and xcase}
+ case Xcase of {if y is at top boundary}
+ 1: Ecase:=1; {x at left boundary}
+ 2: Ecase:=2; {x not at a boundary}
+ 3: Ecase:=3; {x at right boundary}
+ end
+ else if y=Ymax then {if y is at bottom boundary}
+ case Xcase of
+ 1: Ecase:=7; {x at left boundary}
+ 2: Ecase:=8; {x not at a boundary}
+ 3: Ecase:=9; {x at right boundary}
+ end
+ else
+ case Xcase of {if y is not at a boundary}
+ 1: Ecase:=4; {x at left boundary}
+ 2: Ecase:=5; {x not at a boundary}
+ 3: Ecase:=6; {x at right boundary}
+ end;
+ Result:=Ecase; {report finding}
+end;
+
+function TForm1.VectorInterpolate(v1, v2, v3, v4: Vector; Xfrac,
+ Yfrac: extended): Vector;
+var
+ NewVect: Vector;
+begin
+ NewVect.x:=Interpolate(v1.x,v2.x,v3.x,v4.x,Xfrac,Yfrac);
+ NewVect.y:=Interpolate(v1.y,v2.y,v3.y,v4.y,Xfrac,Yfrac);
+ NewVect.z:=Interpolate(v1.z,v2.z,v3.z,v4.z,Xfrac,Yfrac);
+ Result:=NewVect;
+end;
+
+function TForm1.Interpolate(val1, val2, val3, val4, Xfrac,
+ Yfrac: extended): extended;
+{provide a value for a point somewhere with four other points which define}
+{the corners of a rectangle. The position of the point in question is given as}
+{a fraction along the x axis and a fraction along the y axis}
+{The value is calculated by linear interpolation along each axis direction}
+var
+ Xgrad,Xgrad1,Xgrad2,Ygrad2,newval: extended;
+begin
+ Xgrad1:=val2-val1; {gradient along top of rectangle}
+ Xgrad2:=val4-val3; {gradient along bottom of rectangle}
+ Ygrad2:=val3-val1; {gradient along left of rectangle}
+ Xgrad:=Xgrad1+Yfrac*(Xgrad2-Xgrad1); {how x axis gradient varies with y}
+ newval:=val1+(Yfrac*Ygrad2)+(Xfrac*Xgrad); {top-left corner value plus }
+ Result:=newval; {contributions from travel down y axis and across x axis}
+end;
+
+procedure TForm1.PlotQuadrant(Bmap: TBitmap; Quadrant: byte; RealX, RealY: extended);
+{Use the PntArray configured by PlotPoint and the supplied variables such as }
+{Quadrant number (1,2,3 or 4) and actual (x,y) location for grid point. The }
+{four points defining the quadrant are sent to VectorInterpolate to determine}
+{the new RGB value for each pixel in the quadrant which is to be plotted.}
+{Note: only a quarter of the area defined by the quadrant is actually }
+{calculated and drawn, as adjacent points will do the other three quarters}
+{when they are calculated.}
+var
+ xstart,ystart,xend,yend,i,j: smallint;
+ v1,v2,v3,v4,pix: Vector;
+ colour: Tcolor;
+ Xofs,Yofs: extended;
+ Rval,Gval,Bval: byte;
+ Xpos,Ypos: smallint;
+ Width,Height,HalfWidth,HalfHeight: extended;
+begin
+ Xofs:=0;
+ Yofs:=0;
+ xstart:=0;
+ ystart:=0;
+ xend:=0;
+ yend:=0;
+ if TileZ then begin
+ HalfWidth:=TileHalfX;
+ HalfHeight:=TileHalfY;
+ Width:=TileScrScaleX;
+ Height:=TileScrScaleX;
+ end
+ else begin
+ HalfWidth:=halfX;
+ HalfHeight:=halfY;
+ Width:=ScrScaleX;
+ Height:=ScrScaleY;
+ end;
+{Determine boundary conditions for relevant Quadrant. The origin of the four}
+{Quadrants is condidered to be point (0,0) for the purposes of the calculation}
+ case Quadrant of {Quadrant 1}
+ 1: begin {x<=0, y<=0}
+ xstart:=-Trunc(HalfWidth)-1;
+ ystart:=-Trunc(HalfHeight)-1;
+ xend:=0;
+ yend:=0;
+ Xofs:=Width;
+ Yofs:=Height;
+ end; {Quadrant 2}
+ 2: begin {x>0, y<=0}
+ xstart:=0;
+ ystart:=-Trunc(HalfHeight)-1;
+ xend:=Trunc(Width-HalfWidth)+1;
+ yend:=0;
+ Xofs:=0;
+ Yofs:=Height;
+ end; {Quadrant 3}
+ 3: begin {x<=0, y>0}
+ xstart:=-Trunc(HalfWidth)-1;
+ ystart:=0;
+ xend:=0;
+ yend:=Trunc(Height-HalfHeight)+1;
+ Xofs:=Width;
+ Yofs:=0;
+ end; {Quadrant 4}
+ 4: begin {x>0, y>0}
+ xstart:=0;
+ ystart:=0;
+ xend:=Trunc(Width-HalfWidth)+1;
+ yend:=Trunc(Height-HalfHeight)+1;
+ Xofs:=0;
+ Yofs:=0;
+ end;
+ end;
+
+ if TileZ then with TileRect do begin {Trim edges, so it fits exactly}
+ if (RealX+xstart)<=(Left+EdgeSize) then xstart:=Round2(Left+EdgeSize-RealX);
+ if (RealX+xend)>=(Right-1) then xend:=Round2(Right-1-RealX);
+ if (RealY+ystart)<=(Top+EdgeSize) then ystart:=Round2(Top+EdgeSize-RealY);
+ if (RealY+yend)>=(Bottom-1) then yend:=Round2(Bottom-1-RealY);
+ end;
+
+ if Quadrant>2 then Inc(Quadrant); {Algorithm for selecting the appropriate points}
+ v1:=PntArray[Quadrant];
+ v2:=PntArray[Quadrant+1];
+ v3:=PntArray[Quadrant+3];
+ v4:=PntArray[Quadrant+4];
+
+ for j:=ystart to yend do begin {scan each horizontal line in the Quadrant}
+ Ypos:=Round2(RealY+j); {Determine actual y coord for point in Quadrant}
+ for i:=xstart to xend do begin {scan along horizontal line in Quadrant}
+ {do the linear interpolation for each colour of point in Quadrant}
+ pix:=VectorInterpolate(v1,v2,v3,v4,((i+Xofs)/Width),((j+Yofs)/Height));
+ with pix do begin
+ Rval:=byte(Round2(abs(x))); {convert real values to integers}
+ Gval:=byte(Round2(abs(y))); {round values to nearest integer (down if 0.5)}
+ Bval:=byte(Round2(abs(z)));
+ end;
+ {if greyscale display is required, the R,G & B values are all equalized}
+ {prior to building the ColourArray and calling the PlotPoint and }
+ {PlotQuadrant routines, so the resulting colour is guaranteed to also}
+ {be a greyscale.}
+
+ Colour:=Tcolor((Rval*RED) + (Gval*GREEN) + (Bval*BLUE)); {combine values to give one RGB value}
+ Xpos:=Round2(RealX+i); {calc x coord of the point on the Image control}
+ PlotPixel(Xpos,Ypos,Colour);
+ end;
+ end;
+end;
+
+function TForm1.GetActualX(x: smallint): smallint;
+{return the actual screen x coordinate (in the picture control) of the x }
+{coord of a point in the grid (assumes bitmap to be displayed at full size)}
+begin
+ Result:=round2(GetRealX(x)); {ScrScaleX=number of pixels b/w points}
+end;
+
+function TForm1.GetActualY(y: smallint): smallint;
+{return the actual screen y coordinate (in the picture control) of the y }
+{coord of a point in the grid (assumes bitmap to be displayed at full size)}
+begin
+ Result:=round2(GetRealY(y)); {ScrScaleY=number of pixels b/w points}
+end;
+
+procedure TForm1.VectorSpacingChange(Sender: TObject);
+{Redraw screen with different arrow spacing, unless Z plane tiling is }
+{on in which case arrows are not shown anyhow.}
+var
+ step: integer;
+begin
+ step:=VectSpacing;
+
+ try
+ step:=StrToInt(VectorSpacing.Text);
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ VectorSpacing.Text:='';
+ end;
+
+ New_VectSpacing:=step;
+
+ if not TileZ then DoUpdate:=true;
+end;
+
+procedure TForm1.SetTileSize;
+{If the Z Plane tiling option is selected, each of the Z coordinate X/Y planes}
+{is to be displayed simultaneously on the Image control (screen). So, as the }
+{dimensions of the grid (including the number of Z planes) can vary, the }
+{optimum tile size must be calculated so that all planes can be displayed }
+{with their correct aspect ratios and at the largest possible tile size}
+{Note: A tile is a small version of one of the X/Y planes which are normally}
+{ displayed as a full screen image.}
+var
+ nx,ny: smallint;
+ height: integer;
+ TileAspect: extended;
+begin
+ if MaintainAspect then
+ TileAspect:=Aspect
+ else
+ TileAspect:=ScreenAspect;
+
+ TileX:=(BitmapX-EdgeSize*2); {start with one tile the width of the screen}
+ repeat {TileX will be width of tile}
+ nx:=(BitmapX-EdgeSize*2) div TileX; {nx is the number of tiles across the screen}
+ TileY:=Trunc(TileAspect*TileX); {TileY will be height of tile}
+ ny:=GridDepth div nx; {ny is number of rows of tiles down the screen}
+ if (GridDepth mod nx)<>0 then Inc(ny);
+ height:=ny*TileY; {total height used by tiles}
+ Dec(TileX); {Try smaller tile size}
+{height must fit screen. Don't allow vanishingly small. Don't exceed max Z plane}
+ until (height<=(BitmapY-EdgeSize*2)) or (TileX<10) or (nx>GridDepth);
+ Inc(TileX); {reverse the last decrement}
+ if Render=OneToOne then begin {If one to one representation required}
+ if TileX>GridWidth then begin {restrict max tile size so that}
+ TileX:=GridWidth; {one grid point becomes one pixel}
+ TileY:=Trunc(TileAspect*TileX);
+ end;
+ if TileY>GridHeight then begin
+ TileY:=GridHeight;
+ TileX:=Trunc(TileY/TileAspect);
+ end;
+ end;
+ TileXcount:=(BitmapX-EdgeSize*2) div TileX; {determine number across...}
+ TileYcount:=GridDepth div TileXcount; {and down screen.}
+ if GridDepth mod TileXcount<>0 then Inc(TileYcount); {add one for an incmplete row}
+ if MaintainAspect then begin
+ TileScrScaleX:=(TileX-EdgeSize)/GridWidth; {calc scaling factors for reducing full}
+ TileScrScaleY:=(TileY-EdgeSize)/GridHeight; {screen to tile size (allow for border)}
+ end
+ else begin
+ TileScrScaleX:=((TileX-EdgeSize)/BitmapX)*ScrScaleX; {calc scaling factors for reducing full}
+ TileScrScaleY:=((TileY-EdgeSize)/BitmapY)*ScrScaleY; {screen to tile size (allow for border)}
+ end;
+ with TileGrid do begin
+ ColCount:=TileXcount;
+ RowCount:=TileYcount;
+ DefaultColWidth:=TileX;
+ DefaultRowHeight:=TileY;
+ end;
+end;
+
+function TForm1.Round2(realval: extended): int64;
+{This function provided an equal, consistent rounding of real numbers}
+{such that they are always rounded to the nearest integer, and when }
+{exactly 0.5 between integers, they are rounded towards zero.}
+{The standard Round function provided rounds to the EVEN integer!!}
+var
+ intval: int64;
+ fraction: extended;
+begin
+ intval:=Trunc(realval); {first round real value towards zero}
+ fraction:=(realval-intval); {subtract this result from the real}
+ if fraction>0.5 then Inc(intval) {if the fraction>0.5, add one to intval}
+ else if fraction<-0.5 then Dec(intval); {cater for negative fractions too}
+ Result:=intval; {return the integer value obtained}
+end;
+
+function TForm1.GetRealX(x: extended): extended;
+{performs same function as GetActualX but returns a real value rather than }
+{an integer. This is so cululative rounding errors don't occur in some calcs}
+begin
+ Result:=OriginX+(x*ScrScaleX);
+end;
+
+function TForm1.GetRealY(y: extended): extended;
+{performs same function as GetActualY but returns a real value rather than }
+{an integer. This is so cululative rounding errors don't occur in some calcs}
+begin
+ Result:=OriginY+(y*ScrScaleY);
+end;
+
+function TForm1.ColourRange(value: extended; ScaleFactor: extended): byte;
+{Convert a real value to a colour value (between 0 and 255)}
+var
+ ColourVal: smallint;
+begin
+ ColourVal:=abs(ByteLimit(value*ScaleFactor));
+ Result:=byte(ColourVal);
+end;
+
+function TForm1.VectToColours(vect: vector; ScaleFactor: extended): vector;
+{Takes a vector of real numbers and converts it to a vector of colour}
+{values (one for each component: x,y & z). Negative values become }
+{positive colours.}
+var
+ ColourVect: Vector;
+begin
+ with ColourVect do begin
+ x:=ColourRange(vect.x,ScaleFactor); {convert component values to colour values}
+ y:=ColourRange(vect.y,ScaleFactor);
+ z:=ColourRange(vect.z,ScaleFactor);
+ end;
+ Result:=ColourVect; {return a vector of colour values}
+end;
+
+
+function TForm1.ByteLimit(value: extended): smallint;
+{Take a real value and return it as a smallint value between the limits}
+{-255 and +255}
+var
+ newval: smallint;
+begin
+ if abs(value)>$FF then {if out of range, clip it at the limit}
+ newval:=Sign(value)*$FF
+ else newval:=round2(value);
+ Result:=newval; {return as a smallint}
+end;
+
+function TForm1.VectByteLimit(vect: Vector): Vector;
+{Process each component vector in vect such that the resulting vector's}
+{component vectors are all in the range -255 to 255}
+var
+ ResultVect: Vector;
+begin
+ with ResultVect do begin
+ x:=ByteLimit(vect.x);
+ y:=ByteLimit(vect.y);
+ z:=ByteLimit(vect.z);
+ end;
+ Result:=ResultVect;
+end;
+
+function TForm1.VectorProperty(field: byte; Apoint: point): Vector;
+{Return a vector quantity of the field which is required to be displayed}
+{using the Electric and Magnetic field vectors at a grid point.}
+var
+ Vect: Vector;
+begin
+ Vect:=NullVect;
+ with Apoint do
+ case Field of {depending on which field is required to display}
+ PSI_VECTOR_FIELD: Vect:=PsiVect;
+ ELECTRIC_FIELD,E_ELECTRIC_FIELD: Vect:=Electric; {Show Electric Field}
+ MAGNETIC_FIELD,E_MAGNETIC_FIELD: Vect:=Magnetic; {Show Magnetic Field}
+ POWER_FLOW_FIELD: Vect:=PowerFlow(Apoint); {Show Power flow}
+ HERTZIAN_FIELD: Vect:=Hertzian;
+ VECTOR_POTENTIAL_FIELD: Vect:=VectorPotential;
+ PSI_CURL_VECTOR_FIELD: Vect:=PsiCurlVect;
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PARTICLE_POS_REFLECTED_FIELD: Vect:=particle_pos_Reflected;
+ PARTICLE_NEG_REFLECTED_FIELD: Vect:=particle_neg_Reflected;
+{$IFEND}
+ end;
+ Result:=Vect;
+end;
+
+function TForm1.PointNull(Apoint: point; DisplayField:smallint): boolean;
+{See if the point's information is all zeros}
+var
+ isNull: boolean;
+begin
+ with Apoint do begin
+ case DisplayField of
+ PSI_VECTOR_FIELD: isNull:=VectorNull(PsiVect);
+ ELECTRIC_FIELD: isNull:=VectorNull(Electric);
+ MAGNETIC_FIELD: isNull:=VectorNull(Magnetic);
+ POWER_FLOW_FIELD: isNull:=VectorNull(PowerFlow(Apoint));
+ HERTZIAN_FIELD: isNull:=VectorNull(Hertzian);
+ VECTOR_POTENTIAL_FIELD: isNull:=VectorNull(VectorPotential);
+ PSI_CURL_VECTOR_FIELD: isNull:=VectorNull(PsiCurlVect);
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PARTICLE_POS_REFLECTED_FIELD: isNull:=VectorNull(particle_pos_Reflected);
+ PARTICLE_NEG_REFLECTED_FIELD: isNull:=VectorNull(particle_neg_Reflected);
+{$IFEND}
+ end;
+ end;
+ Result:=isNull;
+end;
+
+function TForm1.VectorNull(vect: Vector): boolean;
+{Look at each component vector to see if the vector is overall a}
+{Null vector.}
+begin
+ with vect do
+ if (x=0) and (y=0) and (z=0) then
+ Result:=true else Result:=false;
+end;
+
+function TForm1.ReverseTColor(input: TColor): Tcolor;
+{Function reverses the byte order of a TColor type. This is required}
+{prior to storing in bitmap's memory using the pointers provided by}
+{the ScanLine function.}
+var
+ Byte1,Byte2,Byte3: byte;
+begin
+ if input<>0 then begin
+ Byte1:=PByteArray(@input)[0];
+ Byte2:=PByteArray(@input)[1];
+ Byte3:=PByteArray(@input)[2];
+ Result:=Byte3*RED + Byte2*Green + Byte1*Blue;
+ end
+ else Result:=0;
+end;
+
+procedure TForm1.Z_TilingClick(Sender: TObject);
+begin
+ if TileZ then New_TileZ:=false else New_TileZ:=true;
+ DoUpdate:=true;
+end;
+
+function TForm1.MouseZplane: smallint;
+{If Z plane tiling is being used, return the tile number which}
+{the mouse cursor is over. Zero returned if not over a tile.}
+var
+ x,y: longint;
+ Coord: TPoint;
+ Coord2: TGridCoord;
+ Tile: smallint;
+begin
+ if TileZ then begin
+ with Form1 do begin
+ x:=left+MainGroup.left+TileGrid.left+3;
+ y:=top+(Height-ClientHeight)+MainGroup.top+TileGrid.top-3;
+ end;
+ Coord:=MyMouse.CursorPos;
+ Coord2:=TileGrid.MouseCoord(Coord.x-x,Coord.y-y);
+ Tile:=Coord2.x+Coord2.y*TileXcount;
+ if (Tile>GridDepth-1) or (Tile<0) then Tile:=-1; {ensure in range}
+ Result:=Tile;
+ end
+ else
+ Result:=-1;
+end;
+
+procedure TForm1.Image1Click(Sender: TObject);
+var
+ Tile: smallint;
+begin
+ Tile:=MouseZplane;
+ if Tile>=0 then New_ZPlane:=Tile;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Image1DblClick(Sender: TObject);
+var
+ Tile: smallint;
+begin
+ Tile:=MouseZplane;
+ if Tile>=0 then New_ZPlane:=Tile;
+ New_TileZ:=false;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.VectorXClick(Sender: TObject);
+begin
+ VectorChange:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.VectorYClick(Sender: TObject);
+begin
+ VectorChange:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.VectorZClick(Sender: TObject);
+begin
+ VectorChange:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.TileCursor(Bmap: TBitmap; Tile: smallint; colour: TColor);
+{Draw a coloured rectangle around the selected Z Plane Tile}
+var
+ Xcol,Yrow: Longint;
+begin
+ Yrow:=Tile div TileXcount;
+ Xcol:=Tile mod TileXcount;
+ with Bmap.Canvas do begin
+ brush.Color:=colour;
+ FrameRect(TileGrid.CellRect(Xcol,Yrow));
+ end;
+end;
+
+procedure TForm1.Spacing_pixelsClick(Sender: TObject);
+{Redraw screen with different arrow spacing, unless Z plane tiling is }
+{on in which case arrows are not shown anyhow.}
+begin
+ if not TileZ then begin
+ ArrowsUnitsChange:=true;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.Spacing_metresClick(Sender: TObject);
+{Redraw screen with different arrow spacing, unless Z plane tiling is }
+{on in which case arrows are not shown anyhow.}
+begin
+ if not TileZ then begin
+ ArrowsUnitsChange:=true;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.SmoothingCheckBoxClick(Sender: TObject);
+begin
+ smoothing := SmoothingCheckBox.Checked;
+end;
+
+procedure TForm1.EnergyCorrectionCheckBoxClick(Sender: TObject);
+begin
+ EnergyCorrection := EnergyCorrectionCheckBox.Checked;
+end;
+
+procedure TForm1.EFormulaCheckBoxClick(Sender: TObject);
+begin
+ E_useFormula := EFormulaCheckBox.Checked;
+end;
+
+procedure TForm1.HFormulaCheckBoxClick(Sender: TObject);
+begin
+ H_useFormula := HFormulaCheckBox.Checked;
+end;
+
+procedure TForm1.Spacing_gridpointsClick(Sender: TObject);
+{Redraw screen with different arrow spacing, unless Z plane tiling is }
+{on in which case arrows are not shown anyhow.}
+begin
+ if not TileZ then begin
+ ArrowsUnitsChange:=true;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.PlotPixel(x, y: smallint; Colour: TColor);
+{Using the current array of bitmap's horizontal line pointers, plot}
+{a point of a certain 24bitr colour value into memory. The colour must}
+{by reversed prior to storage as the values are stored in byte reversed}
+{order.}
+var
+ YLine: PByteArray;
+begin
+ if (x>0) and (y>0) and (x<=BitmapX) and (y<=BitmapY) then begin
+ Yline:=YLinePtrs[y-1]; {find array of colour values for line y in bitmap}
+ TColorPtr(@Yline[3*(x-1)])^:=ReverseTColor(Colour); {get pointer to 24bit RGB value for point (x,y) }
+ end;
+end;
+
+procedure TForm1.RenderOption1Click(Sender: TObject);
+begin
+ if RenderOption1.Checked then begin
+ New_Render:=OneToOne;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.RenderOption2Click(Sender: TObject);
+begin
+ if RenderOption2.Checked then begin
+ New_Render:=Chunky;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.RenderOption3Click(Sender: TObject);
+begin
+ if RenderOption3.Checked then begin
+ New_Render:=Blend;
+ DoUpdate:=true;
+ end;
+end;
+
+procedure TForm1.RendDisplayClick(Sender: TObject);
+begin
+ if RendDisplay.Checked then
+ New_Rendered:=true
+ else
+ New_Rendered:=false;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.UpdateE_Energy(scr: smallint);
+var
+ i,j,k: smallint;
+begin
+ E_Energy_Tot:=0;
+ for i:=0 to GridWidth-1 do
+ for j:=0 to GridHeight-1 do
+ for k:=0 to GridDepth-1 do with points[scr]^[i,j,k] do
+ E_Energy_Tot:=E_energy_Tot + E_Energy(Electric);
+
+ E_Energy_Tot:=E_energy_Tot*PointVolume; {adjust for grid point volume};
+end;
+
+procedure TForm1.UpdateB_Energy(scr: smallint);
+var
+ i,j,k: smallint;
+begin
+ B_Energy_Tot:=0;
+ for i:=0 to GridWidth-1 do
+ for j:=0 to GridHeight-1 do
+ for k:=0 to GridDepth-1 do with points[scr]^[i,j,k] do
+ B_Energy_Tot := B_Energy_Tot + B_Energy(Magnetic);
+
+ B_Energy_Tot:=B_Energy_Tot*PointVolume; {adjust for grid point volume}
+end;
+
+procedure TForm1.AspectControlClick(Sender: TObject);
+begin
+ if AspectControl.Checked then New_MaintainAspect:=true
+ else New_MaintainAspect:=false;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.SetAspectRatio;
+begin
+ Aspect:=GridHeight/GridWidth; {Aspect ratio of X/Y plane in grid}
+ ScrScaleX:=BitmapX/GridWidth; {how many times does grid width fit screen?}
+ ScrScaleY:=BitmapY/GridHeight; {how many times does grid height fit screen?}
+ if MaintainAspect then {if grid aspect ratio is to be preserved,}
+ if ScreenAspect>Aspect then {then adjust scaling values to allow}
+ ScrScaleY:=ScrScaleX*Aspect {the largest image with the same aspect ratio}
+ else
+ ScrScaleX:=ScrScaleY/Aspect;
+ halfX:=ScrScaleX/2; {determine the number of pixels from one point}
+ halfY:=ScrScaleY/2; {to half way to the next point (in x & y directions)}
+ {Determine bitmap coord's of the Origin (top left) of the }
+ {active area of the screen (picture control) where the image will start}
+ OriginX:=Round2((BitmapX-(GridWidth*ScrScaleX))/2);
+ OriginY:=Round2((BitmapY-(GridHeight*ScrScaleY))/2);
+end;
+
+procedure TForm1.GridXChange(Sender: TObject);
+begin
+ try
+ StrToInt(GridX.Text);
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ GridX.Text:='';
+ end;
+end;
+
+procedure TForm1.GridYChange(Sender: TObject);
+begin
+ try
+ StrToInt(GridY.Text);
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ GridY.Text:='';
+ end;
+end;
+
+procedure TForm1.GridZChange(Sender: TObject);
+begin
+ try
+ StrToInt(GridZ.Text);
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ GridZ.Text:='';
+ end;
+end;
+
+procedure TForm1.AcceptGridSizeClick(Sender: TObject);
+{Read the new Grid dimensions and change them to their new values}
+{if they are sensible.}
+begin
+ ProfileCancel();
+
+ try
+ New_GridWidth:=StrToInt(GridX.Text);
+ if New_GridWidth<3 then begin {Keep it in range}
+ GridX.Text:='3';
+ New_GridWidth:=3;
+ end;
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ New_GridWidth:=GridWidth;
+ end;
+ try
+ New_GridHeight:=StrToInt(GridY.Text);
+ if New_GridHeight<3 then begin {Keep it in range}
+ GridY.Text:='3';
+ New_GridHeight:=3;
+ end;
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ New_GridHeight:=GridHeight;
+ end;
+ try
+ New_GridDepth:=StrToInt(GridZ.Text);
+ if New_GridDepth<3 then begin {Keep it in range}
+ GridZ.Text:='3';
+ New_GridDepth:=3;
+ end;
+ except {catch any invalid integer conditions}
+ on E: Exception do
+ New_GridDepth:=GridDepth;
+ end;
+
+ if (New_GridWidth*New_GridHeight*New_GridDepth) > (GRID_LIMIT*GRID_LIMIT*GRID_LIMIT) then begin
+ ShowMessage('Dimensions too large - reverting.');
+ New_GridWidth:=GridWidth;
+ New_GridHeight:=GridHeight;
+ New_GridDepth:=GridDepth;
+ GridX.Text:=IntToStr(GridWidth);
+ GridY.Text:=IntToStr(GridHeight);
+ GridZ.Text:=IntToStr(GridDepth);
+ end
+ else begin
+ DoUpdate:=true;
+ Restart:=true;
+ end;
+end;
+
+procedure ProcSetGridGlobals(Form: TForm1);
+{Set the values of various global variables which are dependent on the Grid}
+{size chosen.}
+var
+ newWidth: extended;
+begin
+ try
+ newWidth:=strtofloat(Form.ActualGridWidth.Text);
+
+ if (newWidth=0) then
+ newWidth:=ActualWidth;
+ except
+ on E: Exception do
+ newWidth:=ActualWidth;
+ end;
+
+ PPMx:=New_GridWidth/newWidth;
+ PPMy:=New_GridHeight/newWidth;
+ PPMz:=New_GridDepth/newWidth;
+
+ {size, in metres, that each point represents}
+ dx:=1/PPMx;
+ dy:=1/PPMy;
+ dz:=1/PPMz;
+
+ ActualWidth:=GridWidth*dx; {Actual width the screen models - in metres}
+ ActualHeight:=GridHeight*dy; {Actual Height the screen models - in metres}
+ ActualDepth:=GridDepth*dz; {Actual Depth the screen models - in metres}
+ PointArea:=dx*dy; {Area each pixel represents}
+ PointVolume:=dx*dy*dz; {volume each pixel represents}
+ Form.ZPlane.Max:=GridDepth; {set the ZPlane control's max position}
+ New_ZPlane:=round(GridDepth/2); {default start point is mid point in Z axis}
+ Form.LastZ.Caption:=IntToStr(GridDepth); {show max Z plane value under ZPlane control}
+
+ DoUpdate:=true;
+end;
+
+procedure TForm1.SetGridGlobals;
+{Set the values of various global variables which are dependent on the Grid}
+{size chosen.}
+begin
+ ProcSetGridGlobals(Self);
+end;
+
+function GetLargestFreeMemRegion(var AAddressOfLargest: pointer): LongWord;
+var
+ Si: TSystemInfo;
+ P, dwRet: LongWord;
+ Mbi: TMemoryBasicInformation;
+begin
+ Result := 0;
+ AAddressOfLargest := nil;
+ GetSystemInfo(Si);
+ P := 0;
+ while P < LongWord(Si.lpMaximumApplicationAddress) do begin
+ dwRet := VirtualQuery(pointer(P), Mbi, SizeOf(Mbi));
+ if (dwRet > 0) and (Mbi.State and MEM_FREE <> 0) then begin
+ if Result < Mbi.RegionSize then begin
+ Result := Mbi.RegionSize;
+ AAddressOfLargest := Mbi.BaseAddress;
+ end;
+ Inc(P, Mbi.RegionSize);
+ end else
+ Inc(P, Si.dwPageSize);
+ end;
+end;
+
+procedure TForm1.ReAllocGridMemory;
+{Try and allocate memory for the Grid of data points. If successful}
+{Adopt the new Dimensions. Only newly allocated memory is initialised}
+var
+ NewSizeOK, retried: boolean;
+ scr,i,j,k,n: integer;
+ Height, Width, Depth: integer;
+ BaseAddr: pointer;
+ MemSize: LongWord;
+begin
+ Width:=10;
+ Height:=10;
+ Depth:=10;
+
+ n:=0;
+ retried:=false;
+
+ while n < 2 do begin
+ Inc(n);
+
+ if n = 2 then begin
+ Width:=New_GridWidth;
+ Height:=New_GridHeight;
+ Depth:=New_GridDepth;
+ end;
+
+ // MemSize := GetLargestFreeMemRegion(BaseAddr);
+ NewSizeOK:=true;
+ try
+ SetLength(points1,Width,Height,Depth); {set size of Grid}
+ // SetLength(points2,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+
+// if n=1 then continue;
+
+// if NewSizeOK then
+ try
+ SetLength(ColourArray,Width,Height);
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(SignArray,Width,Height,3);
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle1_A,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle2_A,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle1_E,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle2_E,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle_1_2_B,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle1_Power,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+// if NewSizeOK then
+ try
+ SetLength(particle2_Power,Width,Height,Depth); {set size of Grid}
+ except
+ on E : Exception do NewSizeOK:=false;
+ end;
+
+ if NewSizeOK then begin {Ensure new space is initialised}
+ scr:=0;
+ // for scr:=0 to 1 do
+ for i:=0 to (Width-2) do
+ for j:=0 to (Height-2) do
+ for k:=0 to (Depth-2) do
+ points[scr]^[i,j,k]:=NullPoint;
+ end
+ else begin
+ if retried then exit;
+
+ ShowMessage('Dimensions too large - reverting.');
+ New_GridWidth:=GridWidth; {Memory allocation failed, so }
+ New_GridHeight:=GridHeight; {return to previous Dimensions}
+ New_GridDepth:=GridDepth;
+
+ n:=1;
+ Width:=10;
+ Height:=10;
+ Depth:=10;
+ retried:=true;
+ end;
+ end; // end for
+end;
+
+procedure TForm1.FormDestroy(Sender: TObject);
+{When the Form closes, De-allocate all the dynamic array memory}
+{allocated during the program's execution.}
+begin
+ Points[0]:=nil; {Free all memory allocated}
+// Points[1]:=nil; {Free all memory allocated}
+ ColourArray:=nil;
+ SignArray:=nil;
+end;
+
+function TForm1.VectorDot(v1, v2: Vector): extended;
+var
+ DotProduct: extended;
+begin
+ DotProduct:=(v1.x*v2.x) + (v1.y*v2.y) + (v1.z*v2.z);
+ Result:=DotProduct;
+end;
+
+function TForm1.Normalize(v: Vector): Vector;
+var
+ DotProduct, Norm: extended;
+begin
+ DotProduct:=VectorDot(v,v);
+ Norm:=sqrt(DotProduct);
+
+ with v do begin
+ if (Norm > 0) then begin
+ x:=x/Norm;
+ y:=y/Norm;
+ z:=z/Norm;
+ end;
+ end;
+
+ Result:=v;
+end;
+
+function TForm1.ScalarGrad(ScalarGroup: ScalarGrp): Vector;
+{This function is the same as delS }
+{It gives the gradient vector of a Scalar field}
+//
+// { VectGroup's points are assigned as follows: P3 P5
+// P1 P0 P2
+// P4 P6
+//
+// Where P5 & P6 are in the Z plane (P5 at the back and P6 at the front) }
+//
+// Note: the Grid (0,0,0) point is at the Top, Left & Back point of the Grid
+// So X increments to the right, Y increments downwards, & Z increments out of the screen
+var
+ GradVect: Vector;
+begin
+ with ScalarGroup do begin
+ GradVect.x:=((s2-s1)/dx)/nP;
+ GradVect.y:=((s4-s3)/dy)/nP;
+ GradVect.z:=((s6-s5)/dz)/nP;
+ end;
+ Result:=GradVect;
+end;
+
+function TForm1.VectDiv(VectGroup: VectorGrp): extended;
+{This function is the same as Del . Vect (Vector dot product) }
+//
+// { VectGroup's points are assigned as follows: P3 P5
+// P1 P0 P2
+// P4 P6
+//
+// Where P5 & P6 are in the Z plane (P5 at the back and P6 at the front) }
+//
+// Note: the Grid (0,0,0) point is at the Top, Left & Back point of the Grid
+// So X increments to the right, Y increments downwards, & Z increments out of the screen
+
+{Perform the Vector Div function on the vector group passed to it.}
+{The value returned (as a vector) is for the central point of the group}
+var
+ dVx_dx,dVy_dy,dVz_dz: extended;
+begin
+ with VectGroup do begin
+ dVx_dx:=((v2.x - v1.x)/dx)/nP;
+ dVy_dy:=((v4.y - v3.y)/dy)/nP;
+ dVz_dz:=((v6.z - v5.z)/dz)/nP;
+ end;
+
+ Result:=dVx_dx + dVy_dy + dVz_dz;
+end;
+
+function TForm1.VectorCross(v1, v2: Vector): Vector;
+var
+ ResultVect: Vector;
+begin
+ with ResultVect do begin
+ x:=((v1.y)*(v2.z) - (v1.z)*(v2.y));
+ y:=((v1.z)*(v2.x) - (v1.x)*(v2.z));
+ z:=((v1.x)*(v2.y) - (v1.y)*(v2.x));
+ end;
+ Result:=ResultVect;
+end;
+
+function TForm1.VectCurl(VectGroup: VectorGrp): Vector;
+// {This function is the same as Del x Vect (Vector cross product) }
+//
+// {Perform the Vector Curl function on the vector group passed to it.}
+// {The value returned (as a vector) is for the central point of the group}
+//
+// { VectGroup's points are assigned as follows: P3 P5
+// P1 P0 P2
+// P4 P6
+//
+// Where P5 & P6 are in the Z plane (P5 at the back and P6 at the front) }
+//
+// Note: the Grid (0,0,0) point is at the Top, Left & Back point of the Grid
+// So X increments to the right, Y increments downwards, & Z increments out of the screen
+//
+var
+ dVz_dy,dVy_dz,dVx_dz,dVz_dx,dVy_dx,dVx_dy: extended;
+ CurlVect: Vector;
+begin
+ with VectGroup do begin
+ dVz_dy:=((v4.z - v3.z)/dy)/nP;
+ dVy_dz:=((v6.y - v5.y)/dz)/nP;
+ dVx_dz:=((v6.x - v5.x)/dz)/nP;
+ dVz_dx:=((v2.z - v1.z)/dx)/nP;
+ dVy_dx:=((v2.y - v1.y)/dx)/nP;
+ dVx_dy:=((v4.x - v3.x)/dy)/nP;
+ end;
+
+ with CurlVect do begin
+ x:=dVz_dy - dVy_dz;
+ y:=dVx_dz - dVz_dx;
+ z:=dVy_dx - dVx_dy;
+ end;
+
+ Result:=CurlVect;
+end;
+
+function TForm1.PointGroup(scr, x, y, z: smallint): PointGrp;
+{Return a group of point values for the point in question and all}
+{the points immediately adjacent to it. If they are out of the }
+{Grid, assign them zero values.}
+{Assume the starting point (x,y,z) is valid}
+var
+ TheGroup: PointGrp;
+ xless,yless,zless: boolean;
+ xmore,ymore,zmore: boolean;
+begin
+ if x<=0 then xless:=true else xless:=false;
+ if y<=0 then yless:=true else yless:=false;
+ if z<=0 then zless:=true else zless:=false;
+
+ if x>=(GridWidth-1) then xmore:=true else xmore:=false;
+ if y>=(GridHeight-1) then ymore:=true else ymore:=false;
+ if z>=(GridDepth-1) then zmore:=true else zmore:=false;
+
+ { TheGroup's points are assigned as follows: P3 P5
+ P1 P0 P2
+ P4 P6
+
+ Where P5 & P6 are in the Z plane (P5 at the back and P6 at the front) }
+ scr:=0;
+
+ with TheGroup do begin
+ P0:=points[scr]^[x,y,z];
+// if xless then P1:=NullPoint else P1:=points[scr]^[x-1,y,z];
+// if xmore then P2:=NullPoint else P2:=points[scr]^[x+1,y,z];
+// if yless then P3:=NullPoint else P3:=points[scr]^[x,y-1,z];
+// if ymore then P4:=NullPoint else P4:=points[scr]^[x,y+1,z];
+// if zless then P5:=NullPoint else P5:=points[scr]^[x,y,z-1];
+// if zmore then P6:=NullPoint else P6:=points[scr]^[x,y,z+1];
+
+ if xless then P1:=points[scr]^[x+1,y,z] else P1:=points[scr]^[x-1,y,z];
+ if xmore then P2:=points[scr]^[x-1,y,z] else P2:=points[scr]^[x+1,y,z];
+ if yless then P3:=points[scr]^[x,y+1,z] else P3:=points[scr]^[x,y-1,z];
+ if ymore then P4:=points[scr]^[x,y-1,z] else P4:=points[scr]^[x,y+1,z];
+ if zless then P5:=points[scr]^[x,y,z+1] else P5:=points[scr]^[x,y,z-1];
+ if zmore then P6:=points[scr]^[x,y,z-1] else P6:=points[scr]^[x,y,z+1];
+ end;
+ Result:=TheGroup;
+end;
+
+function TForm1.VectorGroup(PntGroup: PointGrp; Field: smallint): VectorGrp;
+{Return a group of vectors for a particular field at, and around the }
+{point in question.}
+var
+ VectGroup: VectorGrp;
+begin
+ with PntGroup do
+ case Field of
+ PSI_VECTOR_FIELD: begin
+ VectGroup.v0:=p0.PsiVect;
+ VectGroup.v1:=p1.PsiVect;
+ VectGroup.v2:=p2.PsiVect;
+ VectGroup.v3:=p3.PsiVect;
+ VectGroup.v4:=p4.PsiVect;
+ VectGroup.v5:=p5.PsiVect;
+ VectGroup.v6:=p6.PsiVect;
+ end;
+
+ ELECTRIC_FIELD: begin
+ VectGroup.v0:=p0.Electric;
+ VectGroup.v1:=p1.Electric;
+ VectGroup.v2:=p2.Electric;
+ VectGroup.v3:=p3.Electric;
+ VectGroup.v4:=p4.Electric;
+ VectGroup.v5:=p5.Electric;
+ VectGroup.v6:=p6.Electric;
+ end;
+
+ MAGNETIC_FIELD: begin
+ VectGroup.v0:=p0.Magnetic;
+ VectGroup.v1:=p1.Magnetic;
+ VectGroup.v2:=p2.Magnetic;
+ VectGroup.v3:=p3.Magnetic;
+ VectGroup.v4:=p4.Magnetic;
+ VectGroup.v5:=p5.Magnetic;
+ VectGroup.v6:=p6.Magnetic;
+ end;
+
+ HERTZIAN_FIELD: begin
+ VectGroup.v0:=p0.Hertzian;
+ VectGroup.v1:=p1.Hertzian;
+ VectGroup.v2:=p2.Hertzian;
+ VectGroup.v3:=p3.Hertzian;
+ VectGroup.v4:=p4.Hertzian;
+ VectGroup.v5:=p5.Hertzian;
+ VectGroup.v6:=p6.Hertzian;
+ end;
+
+ VECTOR_POTENTIAL_FIELD: begin
+ VectGroup.v0:=p0.VectorPotential;
+ VectGroup.v1:=p1.VectorPotential;
+ VectGroup.v2:=p2.VectorPotential;
+ VectGroup.v3:=p3.VectorPotential;
+ VectGroup.v4:=p4.VectorPotential;
+ VectGroup.v5:=p5.VectorPotential;
+ VectGroup.v6:=p6.VectorPotential;
+ end;
+
+ PSI_CURL_VECTOR_FIELD: begin
+ VectGroup.v0:=p0.PsiCurlVect;
+ VectGroup.v1:=p1.PsiCurlVect;
+ VectGroup.v2:=p2.PsiCurlVect;
+ VectGroup.v3:=p3.PsiCurlVect;
+ VectGroup.v4:=p4.PsiCurlVect;
+ VectGroup.v5:=p5.PsiCurlVect;
+ VectGroup.v6:=p6.PsiCurlVect;
+ end;
+
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PARTICLE_POS_REFLECTED_FIELD: begin
+ VectGroup.v0:=p0.particle_pos_Reflected;
+ VectGroup.v1:=p1.particle_pos_Reflected;
+ VectGroup.v2:=p2.particle_pos_Reflected;
+ VectGroup.v3:=p3.particle_pos_Reflected;
+ VectGroup.v4:=p4.particle_pos_Reflected;
+ VectGroup.v5:=p5.particle_pos_Reflected;
+ VectGroup.v6:=p6.particle_pos_Reflected;
+ end;
+
+ PARTICLE_NEG_REFLECTED_FIELD: begin
+ VectGroup.v0:=p0.particle_neg_Reflected;
+ VectGroup.v1:=p1.particle_neg_Reflected;
+ VectGroup.v2:=p2.particle_neg_Reflected;
+ VectGroup.v3:=p3.particle_neg_Reflected;
+ VectGroup.v4:=p4.particle_neg_Reflected;
+ VectGroup.v5:=p5.particle_neg_Reflected;
+ VectGroup.v6:=p6.particle_neg_Reflected;
+ end;
+{$IFEND}
+ else VectGroup:=NullVectGrp;
+ end;
+ Result:=VectGroup;
+end;
+
+function TForm1.ScalarGroup(PntGroup: PointGrp; Field: smallint): ScalarGrp;
+{Return a group of vectors for a particular field at, and around the }
+{point in question.}
+var
+ ScalarGroup: ScalarGrp;
+begin
+ with PntGroup do
+ case Field of
+
+ PSI_SCALAR_FIELD: begin
+ ScalarGroup.s0:=p0.Psi;
+ ScalarGroup.s1:=p1.Psi;
+ ScalarGroup.s2:=p2.Psi;
+ ScalarGroup.s3:=p3.Psi;
+ ScalarGroup.s4:=p4.Psi;
+ ScalarGroup.s5:=p5.Psi;
+ ScalarGroup.s6:=p6.Psi;
+ end;
+
+ ELECTRIC_POTENTIAL_FIELD: begin
+ ScalarGroup.s0:=p0.ElectricPotential;
+ ScalarGroup.s1:=p1.ElectricPotential;
+ ScalarGroup.s2:=p2.ElectricPotential;
+ ScalarGroup.s3:=p3.ElectricPotential;
+ ScalarGroup.s4:=p4.ElectricPotential;
+ ScalarGroup.s5:=p5.ElectricPotential;
+ ScalarGroup.s6:=p6.ElectricPotential;
+ end;
+
+ CHARGE_DENSITY_FIELD: begin
+ ScalarGroup.s0:=p0.ChargeDensity;
+ ScalarGroup.s1:=p1.ChargeDensity;
+ ScalarGroup.s2:=p2.ChargeDensity;
+ ScalarGroup.s3:=p3.ChargeDensity;
+ ScalarGroup.s4:=p4.ChargeDensity;
+ ScalarGroup.s5:=p5.ChargeDensity;
+ ScalarGroup.s6:=p6.ChargeDensity;
+ end;
+
+ else ScalarGroup:=NullScalarGrp;
+ end;
+ Result:=ScalarGroup;
+end;
+
+function TForm1.IntegrateScalarGrp(ScalarGroup: ScalarGrp): extended;
+var
+ Average: extended;
+begin
+ Average:=(ScalarGroup.s0 + ScalarGroup.s1 + ScalarGroup.s2 +
+ ScalarGroup.s3 + ScalarGroup.s4 + ScalarGroup.s5 + ScalarGroup.s6)/7;
+
+ Result:=Average*(dx*dy*dz);
+end;
+
+function TForm1.IsVectorField(Field: smallint): boolean;
+begin
+ case Field of {depending on which field is required to display}
+ PSI_VECTOR_FIELD,
+ ELECTRIC_FIELD,
+ MAGNETIC_FIELD,
+ POWER_FLOW_FIELD,
+ HERTZIAN_FIELD,
+ VECTOR_POTENTIAL_FIELD,
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PSI_CURL_VECTOR_FIELD,
+ PARTICLE_POS_REFLECTED_FIELD,
+ PARTICLE_NEG_REFLECTED_FIELD: begin {Show Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$ELSE}
+ PSI_CURL_VECTOR_FIELD: begin {Show Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$IFEND}
+ Result:=true;
+ end;
+ end;
+ Result:=false;
+end;
+
+procedure TForm1.FindMaxVal(scr, Field: smallint);
+{Find the maximum absolute value of the quantity being displayed, so}
+{that the colour levels can be adjusted to give maximum brightness for}
+{that value.}
+var
+ i,j,k: smallint;
+ vect: Vector;
+ VectorType: boolean;
+ value: extended;
+ Zstart,Zend: smallint;
+begin
+ VectorType:=false;
+ value:=0;
+ MaxVal:=0; {Set it to zero first}
+ if TileZ or scale_3D.Checked then begin {If Z Planes are tiled find Max of whole volume}
+ Zstart:=0;
+ Zend:=GridDepth-1;
+ end
+ else begin
+ Zstart:=Z_Plane; {If not, find Max of current plane only}
+ Zend:=Z_Plane;
+ end;
+
+ for i:=0 to GridWidth-1 do
+ for j:=0 to GridHeight-1 do
+ for k:=Zstart to Zend do begin
+ case Field of {depending on which field is required to use}
+ PSI_VECTOR_FIELD,
+ ELECTRIC_FIELD,
+ MAGNETIC_FIELD,
+ POWER_FLOW_FIELD,
+ HERTZIAN_FIELD,
+ VECTOR_POTENTIAL_FIELD,
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PSI_CURL_VECTOR_FIELD,
+ PARTICLE_POS_REFLECTED_FIELD,
+ PARTICLE_NEG_REFLECTED_FIELD: begin {calc Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$ELSE}
+ PSI_CURL_VECTOR_FIELD: begin {calc Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$IFEND}
+ Vect:=VectorProperty(Field,points[scr]^[i,j,k]);
+ VectorType:=true;
+ end;
+ E_ELECTRIC_FIELD: value:=E_Energy(points[scr]^[i,j,k].Electric); {calc energy in Electric Field}
+ E_MAGNETIC_FIELD: value:=B_Energy(points[scr]^[i,j,k].Magnetic); {calc energy in Magnetic Field}
+ PSI_SCALAR_FIELD: value:=points[scr]^[i,j,k].Psi;
+ ELECTRIC_POTENTIAL_FIELD: value:=points[scr]^[i,j,k].ElectricPotential;
+ CHARGE_DENSITY_FIELD: value:=points[scr]^[i,j,k].ChargeDensity;
+ end;
+
+ if VectorType then with vect do begin
+ MaxVal:=Max(MaxVal,abs(x));
+ MaxVal:=Max(MaxVal,abs(y));
+ MaxVal:=Max(MaxVal,abs(z));
+ end
+ else
+ MaxVal:=Max(MaxVal,abs(value));
+ end;
+end;
+
+procedure TForm1.FindAverageVal(scr, Field: smallint);
+{Find the maximum absolute value of the quantity being displayed, so}
+{that the colour levels can be adjusted to give maximum brightness for}
+{that value.}
+var
+ i,j,k: smallint;
+ vect: Vector;
+ VectorType: boolean;
+ value, average: extended;
+ Zstart,Zend: smallint;
+ count: integer;
+begin
+ VectorType:=false;
+ value:=0;
+ count:=0;
+ average:=0;
+
+ if TileZ or scale_3D.Checked then begin {If Z Planes are tiled find Max of whole volume}
+ Zstart:=0;
+ Zend:=GridDepth-1;
+ end
+ else begin
+ Zstart:=Z_Plane; {If not, find Max of current plane only}
+ Zend:=Z_Plane;
+ end;
+
+ scr:=0;
+
+ for i:=0 to GridWidth-1 do
+ for j:=0 to GridHeight-1 do
+ for k:=Zstart to Zend do begin
+ case Field of {depending on which field is required to use}
+ PSI_VECTOR_FIELD,
+ ELECTRIC_FIELD,
+ MAGNETIC_FIELD,
+ POWER_FLOW_FIELD,
+ HERTZIAN_FIELD,
+ VECTOR_POTENTIAL_FIELD,
+{$IF TWO_PARTICLE_REFLECTION_FIELDS}
+ PSI_CURL_VECTOR_FIELD,
+ PARTICLE_POS_REFLECTED_FIELD,
+ PARTICLE_NEG_REFLECTED_FIELD: begin {calc Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$ELSE}
+ PSI_CURL_VECTOR_FIELD: begin {calc Electric, Magnetic, Power flow, Hertzian, Vector Potential or Electric Potential Fields}
+{$IFEND}
+ Vect:=VectorProperty(Field,points[scr]^[i,j,k]);
+ VectorType:=true;
+ end;
+ E_ELECTRIC_FIELD: value:=E_Energy(points[scr]^[i,j,k].Electric); {calc energy in Electric Field}
+ E_MAGNETIC_FIELD: value:=B_Energy(points[scr]^[i,j,k].Magnetic); {calc energy in Magnetic Field}
+ PSI_SCALAR_FIELD: value:=points[scr]^[i,j,k].Psi;
+ ELECTRIC_POTENTIAL_FIELD: value:=points[scr]^[i,j,k].ElectricPotential;
+ CHARGE_DENSITY_FIELD: value:=points[scr]^[i,j,k].ChargeDensity;
+ end;
+
+ MaxVal:=0; {Set it to zero first}
+
+ if VectorType then with vect do begin
+ MaxVal:=Max(MaxVal,abs(x));
+ MaxVal:=Max(MaxVal,abs(y));
+ MaxVal:=Max(MaxVal,abs(z));
+ end
+ else
+ MaxVal:=Max(MaxVal,abs(value));
+
+ average:=average + MaxVal;
+ Inc(count);
+ end;
+
+ MaxVal:=(average/count)*80;
+end;
+
+procedure TForm1.AutoWarnTimerTimer(Sender: TObject);
+{If the auto-scale warning indicator's timer is active, toggle the}
+{state of the warning indicator at each timer tick.}
+begin
+ AutoWarnState:=not AutoWarnState;
+ if AutoWarnState then
+ AutoWarn.Picture.Graphic:=BitmapRed
+ else
+ AutoWarn.Picture.Graphic:=BitmapBlack;
+end;
+
+procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
+begin
+ Quit:=true;
+end;
+
+procedure TForm1.RateOfTimeChange(Sender: TObject);
+begin
+ New_RateOfTime:=RateOfTime.Position;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.CheckBox12Click(Sender: TObject);
+begin
+ if CheckBox12.Checked then begin
+ New_StartOption:=3;
+ DoUpdate:=true;
+ Restart:=true;
+ two_particle_analysis:=true;
+ end
+ else begin
+ two_particle_analysis:=false;
+ end;
+end;
+
+procedure TForm1.CheckBox1Click(Sender: TObject);
+begin
+ if CheckBox1.Checked then begin
+ CheckBox2.Enabled:=true;
+ save_frames:=true;
+ FrameCount:=1;
+ end
+ else begin
+ CheckBox2.Enabled:=false;
+ save_frames:=false;
+ end;
+end;
+
+procedure TForm1.CheckBox2Click(Sender: TObject);
+begin
+ if CheckBox2.Checked then begin
+ save_3D:=true;
+ end
+ else begin
+ save_3D:=false;
+ end;
+end;
+
+procedure TForm1.CheckBox3Click(Sender: TObject);
+begin
+ if CheckBox3.Checked then begin
+ AllFields:=true;
+ end
+ else begin
+ AllFields:=false;
+ end;
+end;
+
+procedure TForm1.Button1Click(Sender: TObject);
+begin
+ New_Flip_YZ:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.ActualGridWidthChange(Sender: TObject);
+var
+ newWidth: extended;
+begin
+ newWidth:=strtofloat(ActualGridWidth.Text);
+
+ if (ActualWidth <> newWidth) then begin
+ if not DoUpdate then ProfileCancel();
+ ProcSetGridGlobals(Self);
+ DoUpdate:=true;
+ Restart:=true;
+ end;
+end;
+
+procedure TForm1.ArrowScaleScrollChange(Sender: TObject);
+begin
+ New_ArrowScaleFactor := ArrowScaleScroll.Position;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Button2Click(Sender: TObject);
+begin
+ Restart:=true;
+ DoUpdate:=true;
+end;
+
+procedure TForm1.ViewFromTopClick(Sender: TObject);
+begin
+ DoUpdate:=true;
+end;
+
+procedure TForm1.Scale_3DClick(Sender: TObject);
+begin
+ DoUpdate:=true;
+end;
+
+End.
+
diff --git a/VectorPotential.vlb b/VectorPotential.vlb
new file mode 100644
index 0000000..1e13be3
--- /dev/null
+++ b/VectorPotential.vlb
@@ -0,0 +1,463 @@
+[GridXlabel]
+Coordinates=589,418,75,58
+
+[Energy3]
+Coordinates=579,350,62,58
+
+[Start12]
+Coordinates=931,692,56,36
+Visible=True
+
+[Start8]
+Coordinates=872,692,49,36
+
+[Bevel1]
+Coordinates=808,692,54,36
+
+[Energy_Msg3]
+Coordinates=680,282,93,58
+
+[GroupBox2]
+Coordinates=783,282,79,58
+
+[Start2]
+Coordinates=749,692,49,36
+
+[X_Green]
+Coordinates=673,692,66,36
+
+[StatsGroup]
+Coordinates=872,282,79,58
+
+[Y_Red]
+Coordinates=610,692,53,36
+
+[RenderOption3]
+Coordinates=498,692,102,36
+
+[Vect_Arrows]
+Coordinates=920,10,114,58
+
+[ColourButton]
+Coordinates=398,692,90,36
+
+[Start5]
+Coordinates=339,692,49,36
+
+[CheckBox5]
+Coordinates=341,418,114,58
+
+[Auto2]
+Coordinates=281,692,48,36
+
+[RadioButton1]
+Coordinates=179,692,92,36
+
+[CheckBox10]
+Coordinates=515,214,114,58
+
+[Start22]
+Coordinates=113,692,56,36
+
+[VectorY]
+Coordinates=134,214,114,58
+
+[Spacing_Text]
+Coordinates=10,692,93,36
+
+[VectorX]
+Coordinates=10,214,114,58
+
+[Edit2]
+Coordinates=558,146,44,58
+
+[Z_grey]
+Coordinates=1040,646,54,36
+
+[Z_Plane_Number]
+Coordinates=296,78,115,58
+
+[CheckBox9]
+Coordinates=581,78,114,58
+
+[RenderOption2]
+Coordinates=928,646,102,36
+
+[Spacing_metres]
+Coordinates=811,646,107,36
+
+[CheckBox3]
+Coordinates=387,10,114,58
+
+[Energy4]
+Coordinates=1067,350,62,58
+
+[Label2]
+Coordinates=10,418,53,58
+
+[Start1]
+Coordinates=752,646,49,36
+
+[Units2]
+Coordinates=174,350,51,58
+
+[Z_Tiling]
+Coordinates=10,350,61,58
+
+[Vector_Group]
+Coordinates=639,214,94,58
+
+[Field9]
+Coordinates=692,646,50,36
+
+[Start11]
+Coordinates=626,646,56,36
+
+[AutoWarnTimer]
+Coordinates=1336,111,104,36
+
+[GridZlabel]
+Coordinates=919,146,74,58
+
+[CheckBox8]
+Coordinates=705,78,114,58
+
+[Z_Red]
+Coordinates=563,646,53,36
+
+[CheckBox6]
+Coordinates=511,10,114,58
+
+[GridX]
+Coordinates=524,78,47,58
+
+[Image1]
+Coordinates=320,10,57,58
+
+[ColourX_Group]
+Coordinates=253,146,104,58
+
+[FieldGroup]
+Coordinates=828,418,78,58
+
+[Start21]
+Coordinates=497,646,56,36
+
+[GridGroup]
+Coordinates=123,486,74,58
+
+[X_none]
+Coordinates=428,646,59,36
+
+[Spacing_pixels]
+Coordinates=317,646,101,36
+
+[X_grey]
+Coordinates=252,646,55,36
+
+[ViewFromTop]
+Coordinates=258,214,114,58
+
+[SmoothingCheckBox]
+Coordinates=73,418,134,58
+
+[Start6]
+Coordinates=193,646,49,36
+
+[LastZ]
+Coordinates=136,646,47,36
+
+[Units3]
+Coordinates=454,214,51,58
+
+[Z_Colour]
+Coordinates=916,418,67,58
+
+[AutoScaleGroup]
+Coordinates=292,350,109,58
+
+[Start10]
+Coordinates=70,646,56,36
+
+[TimeDisplay]
+Coordinates=829,78,85,58
+
+[Field8]
+Coordinates=10,646,50,36
+
+[Energy1]
+Coordinates=1050,78,62,58
+
+[Field5]
+Coordinates=1087,600,50,36
+
+[DisplayLevel]
+Coordinates=989,600,88,36
+
+[CheckBox12]
+Coordinates=196,10,114,58
+
+[ColourZ_Group]
+Coordinates=10,486,103,58
+
+[CheckBox4]
+Coordinates=217,418,114,58
+
+[Y_Blue]
+Coordinates=923,600,56,36
+
+[CheckBox11]
+Coordinates=465,418,114,58
+
+[DisplayOptionsGroup]
+Coordinates=635,10,137,58
+
+[Energy_Msg2]
+Coordinates=651,350,93,58
+
+[Scale_3D]
+Coordinates=743,214,114,58
+
+[Y_grey]
+Coordinates=858,600,55,36
+
+[Label3]
+Coordinates=95,282,53,58
+
+[FirstZ]
+Coordinates=800,600,48,36
+
+[RendDisplay]
+Coordinates=221,282,114,58
+
+[DistBetweenUnits]
+Coordinates=64,146,116,58
+
+[Label1]
+Coordinates=367,146,53,58
+
+[Label4]
+Coordinates=190,146,53,58
+
+[Energy_Msg1]
+Coordinates=421,78,93,58
+
+[X_Blue]
+Coordinates=734,600,56,36
+
+[Field7]
+Coordinates=674,600,50,36
+
+[Start19]
+Coordinates=608,600,56,36
+
+[Start14]
+Coordinates=542,600,56,36
+
+[Auto1]
+Coordinates=484,600,48,36
+
+[VectorSpacing]
+Coordinates=10,10,98,58
+
+[TimeFreeze]
+Coordinates=674,418,83,58
+
+[Timesteps]
+Coordinates=400,600,74,36
+
+[AmpDisplay]
+Coordinates=81,350,83,58
+
+[Start17]
+Coordinates=334,600,56,36
+
+[Start7]
+Coordinates=275,600,49,36
+
+[Start15]
+Coordinates=209,600,56,36
+
+[Edit1]
+Coordinates=10,146,44,58
+
+[Z_Green]
+Coordinates=134,600,65,36
+
+[Start16]
+Coordinates=68,600,56,36
+
+[DistBetweenLabel]
+Coordinates=430,146,118,58
+
+[Auto4]
+Coordinates=10,600,48,36
+
+[Field1]
+Coordinates=1080,554,50,36
+
+[ReScale]
+Coordinates=1007,554,63,36
+
+[RenderOption1]
+Coordinates=895,554,102,36
+
+[Button2]
+Coordinates=10,78,59,58
+
+[Start13]
+Coordinates=829,554,56,36
+
+[Start9]
+Coordinates=770,554,49,36
+
+[StartGroup]
+Coordinates=411,350,77,58
+
+[TileGrid]
+Coordinates=700,554,60,36
+
+[Z_none]
+Coordinates=632,554,58,36
+
+[ColourGroup]
+Coordinates=991,214,88,58
+
+[Button1]
+Coordinates=981,78,59,58
+
+[Y_none]
+Coordinates=563,554,59,36
+
+[Field3]
+Coordinates=503,554,50,36
+
+[VectorZ]
+Coordinates=867,214,114,58
+
+[Start4]
+Coordinates=444,554,49,36
+
+[GridYlabel]
+Coordinates=10,282,75,58
+
+[Field4]
+Coordinates=384,554,50,36
+
+[Start18]
+Coordinates=318,554,56,36
+
+[ZPlane]
+Coordinates=253,554,55,36
+
+[ZPlaneGroup]
+Coordinates=754,350,91,58
+
+[ArrowScaleScroll]
+Coordinates=130,554,113,36
+
+[MainGroup]
+Coordinates=855,350,78,58
+
+[GreyscaleButton]
+Coordinates=10,554,110,36
+
+[Y_Green]
+Coordinates=1084,486,66,36
+
+[start3]
+Coordinates=1027,486,47,36
+
+[GridY]
+Coordinates=235,350,47,58
+
+[X_Red]
+Coordinates=964,486,53,36
+
+[Y_Colour]
+Coordinates=118,10,68,58
+
+[RendGroup]
+Coordinates=207,486,81,58
+
+[Start20]
+Coordinates=898,486,56,36
+
+[AcceptGridSize]
+Coordinates=1003,146,103,58
+
+[CheckBox2]
+Coordinates=943,350,114,58
+
+[Label5]
+Coordinates=158,282,53,58
+
+[field6]
+Coordinates=842,486,46,36
+
+[Start23]
+Coordinates=776,486,56,36
+
+[ColourY_Group]
+Coordinates=566,282,104,58
+
+[Units1]
+Coordinates=767,418,51,58
+
+[X_Colour]
+Coordinates=218,78,68,58
+
+[Spacing_gridpoints]
+Coordinates=642,486,124,36
+
+[Z_Blue]
+Coordinates=577,486,55,36
+
+[GridZ]
+Coordinates=924,78,47,58
+
+[Auto3]
+Coordinates=519,486,48,36
+
+[CheckBox7]
+Coordinates=993,418,114,58
+
+[ActualGridWidth]
+Coordinates=961,282,108,58
+
+[HFormulaCheckBox]
+Coordinates=79,78,129,58
+
+[RateOfTime]
+Coordinates=425,486,84,36
+
+[AspectControl]
+Coordinates=345,282,114,58
+
+[EFormulaCheckBox]
+Coordinates=782,10,128,58
+
+[Energy2]
+Coordinates=382,214,62,58
+
+[CheckBox1]
+Coordinates=612,146,114,58
+
+[Field10]
+Coordinates=358,486,57,36
+
+[DistBetween]
+Coordinates=469,282,87,58
+
+[EnergyCorrectionCheckBox]
+Coordinates=736,146,173,58
+
+[AutoWarn]
+Coordinates=498,350,71,58
+
+[Field2]
+Coordinates=298,486,50,36
+
+[]
+Coordinates=0,787,91,36
+
diff --git a/black.bmp b/black.bmp
new file mode 100644
index 0000000..87171d7
Binary files /dev/null and b/black.bmp differ
diff --git a/blue.bmp b/blue.bmp
new file mode 100644
index 0000000..bfa51a1
Binary files /dev/null and b/blue.bmp differ
diff --git a/green.bmp b/green.bmp
new file mode 100644
index 0000000..92e258e
Binary files /dev/null and b/green.bmp differ
diff --git a/grey.bmp b/grey.bmp
new file mode 100644
index 0000000..8ef6c25
Binary files /dev/null and b/grey.bmp differ
diff --git a/red.bmp b/red.bmp
new file mode 100644
index 0000000..5c6fabd
Binary files /dev/null and b/red.bmp differ