Author Topic: Sodium Chloride  (Read 9729 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Sodium Chloride
« Reply #15 on: November 14, 2018, 02:17:09 pm »
I see you dedicated your work here to Pete:

Code: QB64: [Select]
  1. CONST NoBalls%%

;D
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Sodium Chloride
« Reply #16 on: November 14, 2018, 02:33:01 pm »
Maybe so, but at least I have a giant dick following me around. How big? Well if I had to estimate the size, I'd say it could cover a large piece of farmland in Virginia! Is this about the battery thingy? If so, don't blame me. I didn't tell you to buy the energizer brand. They just keep going and going...

Pete :D
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Sodium Chloride
« Reply #17 on: November 14, 2018, 06:27:06 pm »
Hey this reminds me, what happens when you install the batteries backwards in the energizer bunny? Not going and going anymore, but...
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Sodium Chloride
« Reply #18 on: November 14, 2018, 07:55:37 pm »
How do you keep coming up with these? Or... Would you like some assault with your batteries? Just ask Michael Avenatti!

I thought this was an interesting read regarding crystallization: https://phys.org/news/2013-02-theory-crystal-formation.html

@BPlus By the way, not all salt crystals are cubic in nature, although that is said to be the most energetic stable formation...

"Not all salt appears cubic. Try some different brands. Check out Maldon, which has a hollow pyramid shape. Rock Salt is,, well,, rocky shaped. And Cornish Sea Salt almost resembles hailstones."

So I think Qwerkey just needs to rename his project to Cornish Sea Salt Formation. Either that, or stick some batteries backwards in an Energizer bunny.... and run!

Pete

Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Sodium Chloride
« Reply #19 on: November 15, 2018, 04:40:12 am »
Hi! I see (in simulation) some NaCl atom which also make bond with another Na or Cl atom. Is this correct?
As, the NaCl is already stable.
Ashish, you are very perceptive.  This program assumes that sodium and chlorine ions are randomly distributed at prgoram start - yet they would not be ions until a bond is formed.  So, yes, the model is not a good simulation of actual chemistry.  But I had thought that NaCl crystals can form from a water solution where the ions are effectively almost free.  And Pete points us to how complicated that can be.  Interesting, isn't it?

I may do a version where NaCl pairs are already formed at program start and see what happens in my model.

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Sodium Chloride
« Reply #20 on: November 15, 2018, 07:07:47 am »
Here is version 4A.  In this model, NaCl pairs are gradually introduced around the forming crystal.  At first, the forces are only the spherical inverse-square ones of version 1, and so a sphere forms.  When all pairs (125) are in place, the p-orbital orthogonal electronic force is switched on and the crystal forms into a cubic structure.  In some cases, the ions are absent from a lattice place or there can be two ions in one place - I'm introducing lattice defects!  (No, I'm not: it's a rubbish model).  You will find that the build up of the crystal is slow at first and then speeds up.
Code: QB64: [Select]
  1. 'Simple Model of Ionic Crystal v4A by QWERKEY 2018-11-15
  2. '!!! Can get two atoms sitting on the same place - TBF
  3.  
  4. CONST True = -1`, False = 0`
  5. CONST A0! = 100, A1! = 2, R0! = 250, R1! = 2.3, A2! = 200, R2! = 115, FMin! = -5 '-55
  6. CONST TotBalls%% = 125, Atom! = 110, Kelvin! = 0.35, F1! = 1000, F2! = 3000, Xstal! = 0.993, Adjacent! = 0.2
  7. CONST BallSize1%% = 25, BallSize0%% = 30, Offset% = 730, ScreenX% = 1260, ScreenY% = 800
  8.  
  9. DIM SHARED SodiumPos!(TotBalls%% - 1, 2), ChlorinePos!(TotBalls%% - 1, 2) 'Sodium 1, Chlorine 0
  10. DIM SHARED SodiumVel!(TotBalls%% - 1, 2), ChlorineVel!(TotBalls%% - 1, 2), Theta! '= 0.0084
  11. DIM SodiumAcc!(TotBalls%% - 1, 2), ChlorineAcc!(TotBalls%% - 1, 2), BallStats%(1, 2)
  12.  
  13. _TITLE "Very Accurate Quantum Physics Model"
  14.  
  15. FOR N%% = 0 TO TotBalls%% - 1
  16.     FOR M%% = 0 TO 2
  17.         IF N%% = 0 THEN
  18.             ChlorinePos!(N%%, M%%) = Atom! * (RND - 0.5)
  19.         ELSE
  20.             ChlorinePos!(N%%, M%%) = Atom! * (1 + (RND * (1 + (N%% / TotBalls%%))))
  21.             IF RND > 0.5 THEN ChlorinePos!(N%%, M%%) = -ChlorinePos!(N%%, M%%)
  22.         END IF
  23.         ChlorineVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  24.         SodiumVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  25.     NEXT M%%
  26. NEXT N%%
  27. FOR N%% = 0 TO TotBalls%% - 1
  28.     Phi! = 2 * _PI * RND
  29.     Psi! = _PI * RND ' theta
  30.     SodiumPos!(N%%, 2) = ChlorinePos!(N%%, 2) + Atom! * SIN(Psi!) * COS(Phi!)
  31.     SodiumPos!(N%%, 0) = ChlorinePos!(N%%, 0) + Atom! * SIN(Psi!) * SIN(Phi!)
  32.     SodiumPos!(N%%, 1) = ChlorinePos!(N%%, 1) + Atom! * COS(Psi!)
  33. NEXT N%%
  34.  
  35. ' Ball Colours (Cyperium Method)
  36. DATA 0,0,255
  37. DATA 255,0,0
  38. FOR N%% = 0 TO 1
  39.     FOR P%% = 0 TO 2
  40.         READ BallStats%(N%%, P%%)
  41.     NEXT P%%
  42.     TempImage& = _NEWIMAGE(256, 256, 32)
  43.     _DEST TempImage&
  44.     COLOR _RGBA(BallStats%(N%%, 0), BallStats%(N%%, 1), BallStats%(N%%, 2), 65), _RGBA(0, 0, 0, 0)
  45.     'Image data goes from 1 to 255 (not 0 to 255)
  46.     FOR Z% = 128 TO 255
  47.         FOR X% = 1 TO 255
  48.             FOR Y% = 1 TO 255
  49.                 DeltaX% = X% - 127
  50.                 DeltaY% = Y% - 127
  51.                 DeltaZ% = Z% - 127
  52.                 Dist! = SQR((DeltaX% * DeltaX%) + (DeltaY% * DeltaY%) + (DeltaZ% * DeltaZ%))
  53.                 IF Dist! > 125 AND Dist! < 127 THEN PSET (X%, Y%), _RGBA(CINT(Z% * BallStats%(N%%, 0) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 1) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 2) * (1 - (XBright! * X% / 255)) / 255), 65)
  54.             NEXT
  55.         NEXT
  56.     NEXT
  57.     IF N%% = 0 THEN
  58.         Chlorine& = _COPYIMAGE(TempImage&, 33)
  59.     ELSE
  60.         Sodium& = _COPYIMAGE(TempImage&, 33)
  61.     END IF
  62.     _FREEIMAGE TempImage&
  63. NEXT N%%
  64.  
  65. TempImage& = _NEWIMAGE(102, 2, 32)
  66. _DEST TempImage&
  67. LINE (0, 0)-(101, 1), _RGB32(255, 255, 255), BF
  68. LineImage& = _COPYIMAGE(TempImage&, 33)
  69. _FREEIMAGE TempImage&
  70.  
  71. 'Create screen
  72. SCREEN _NEWIMAGE(ScreenX%, ScreenY%, 32)
  73. _DISPLAYORDER _HARDWARE , _SOFTWARE 'do not even render the software layer, just the hardware one.
  74.  
  75. NoBalls%% = 2
  76. Generate` = False
  77. Count% = 0
  78.     _LIMIT 25
  79.     CALL CentreOfMass
  80.     MaxDist! = 0
  81.     FOR N%% = 0 TO NoBalls%% - 1
  82.         XTemp! = XDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2))): ZTemp! = ZDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2)))
  83.         _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Chlorine& TO(-(BallSize1%% - 1) \ 2 + XTemp!, (BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((BallSize1%% - 1) \ 2 + XTemp!, (BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(BallSize1%% - 1) \ 2 + XTemp!, -(BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  84.         _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Chlorine& TO((BallSize1%% - 1) \ 2 + XTemp!, -(BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(BallSize1%% - 1) \ 2 + XTemp!, -(BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((BallSize1%% - 1) \ 2 + XTemp!, (BallSize1%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  85.         XTemp! = XDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2))): ZTemp! = ZDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2)))
  86.         _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Sodium& TO(-(BallSize0%% - 1) \ 2 + XTemp!, (BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((BallSize0%% - 1) \ 2 + XTemp!, (BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(BallSize0%% - 1) \ 2 + XTemp!, -(BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  87.         _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Sodium& TO((BallSize0%% - 1) \ 2 + XTemp!, -(BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(BallSize0%% - 1) \ 2 + XTemp!, -(BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((BallSize0%% - 1) \ 2 + XTemp!, (BallSize0%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  88.         FOR M%% = 0 TO 2
  89.             SodiumAcc!(N%%, M%%) = 0
  90.         NEXT M%%
  91.         FOR M%% = 0 TO 2
  92.             ChlorineAcc!(N%%, M%%) = 0
  93.         NEXT M%%
  94.         FOR L%% = 0 TO NoBalls%% - 1
  95.             'opposites
  96.             D! = SQR((SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  97.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  98.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  99.             FOR M%% = 0 TO 2
  100.                 SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  101.             NEXT M%%
  102.             IF D! < Atom! THEN
  103.                 '_MAPTRIANGLE (0, 0)-(101, 0)-(101, 1), LineImage& TO(XDash!(SodiumPos!(N%%, 0), SodiumPos!(N%%, 2)), SodiumPos!(N%%, 1), ZDash!(SodiumPos!(N%%, 0), SodiumPos!(N%%, 2)) - Offset%)-(XDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)), ChlorinePos!(L%%, 1), ZDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)) - Offset%)-(XDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)), ChlorinePos!(L%%, 1), ZDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)) - Offset% - 1), , _SMOOTH
  104.                 IF NoBalls%% = TotBalls%% THEN
  105.                     IF ABS(SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) > ABS(SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) AND ABS(SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) > ABS(SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)) THEN
  106.                         delta! = SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)
  107.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  108.                             SodiumPos!(N%%, 1) = SodiumPos!(N%%, 1) + delta! * (1 - Xstal!)
  109.                             ChlorinePos!(L%%, 1) = ChlorinePos!(L%%, 1) - delta! * (1 - Xstal!)
  110.                         END IF
  111.                         delta! = SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)
  112.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  113.                             SodiumPos!(N%%, 2) = SodiumPos!(N%%, 2) + delta! * (1 - Xstal!)
  114.                             ChlorinePos!(L%%, 2) = ChlorinePos!(L%%, 2) - delta! * (1 - Xstal!)
  115.                         END IF
  116.                     ELSEIF ABS(SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) > ABS(SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) AND ABS(SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) > ABS(SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)) THEN
  117.                         delta! = SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)
  118.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  119.                             SodiumPos!(N%%, 0) = SodiumPos!(N%%, 0) + delta! * (1 - Xstal!)
  120.                             ChlorinePos!(L%%, 0) = ChlorinePos!(L%%, 0) - delta! * (1 - Xstal!)
  121.                         END IF
  122.                         delta! = SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)
  123.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  124.                             SodiumPos!(N%%, 2) = SodiumPos!(N%%, 2) + delta! * (1 - Xstal!)
  125.                             ChlorinePos!(L%%, 2) = ChlorinePos!(L%%, 2) - delta! * (1 - Xstal!)
  126.                         END IF
  127.                     ELSE
  128.                         delta! = SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)
  129.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  130.                             SodiumPos!(N%%, 1) = SodiumPos!(N%%, 1) + delta! * (1 - Xstal!)
  131.                             ChlorinePos!(L%%, 1) = ChlorinePos!(L%%, 1) - delta! * (1 - Xstal!)
  132.                         END IF
  133.                         delta! = SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)
  134.                         IF ABS(delta!) > Adjacent! * Atom! THEN
  135.                             SodiumPos!(N%%, 0) = SodiumPos!(N%%, 0) + delta! * (1 - Xstal!)
  136.                             ChlorinePos!(L%%, 0) = ChlorinePos!(L%%, 0) - delta! * (1 - Xstal!)
  137.                         END IF
  138.                     END IF
  139.                 END IF
  140.                 IF N%% = NoBalls%% - 1 AND L%% < N%% AND NOT Generate` THEN
  141.                     Generate` = True
  142.                 END IF
  143.             END IF
  144.             D! = SQR((SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) * (SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) + (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) * (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) + (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)) * (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)))
  145.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  146.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  147.             FOR M%% = 0 TO 2
  148.                 ChlorineAcc!(N%%, M%%) = F! * (SodiumPos!(L%%, M%%) - ChlorinePos!(N%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  149.             NEXT M%%
  150.             IF D! < Atom! THEN
  151.                 IF N%% = NoBalls%% - 1 AND L%% < N%% AND NOT Generate` THEN
  152.                     Generate` = True
  153.                 END IF
  154.             END IF
  155.             IF L%% <> N%% THEN
  156.                 'same type
  157.                 D! = SQR((SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) * (SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) + (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) * (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) + (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)) * (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)))
  158.                 F! = -(Attraction!(D!)) / F2!
  159.                 FOR M%% = 0 TO 2
  160.                     SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - SodiumPos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  161.                 NEXT M%%
  162.                 D! = SQR((ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  163.                 F! = -(Attraction!(D!)) / F2!
  164.                 FOR M%% = 0 TO 2
  165.                     ChlorineAcc!(N%%, M%%) = -F! * (ChlorinePos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  166.                 NEXT M%%
  167.             END IF
  168.         NEXT L%%
  169.         FOR M%% = 0 TO 2
  170.             SodiumPos!(N%%, M%%) = SodiumPos!(N%%, M%%) + SodiumVel!(N%%, M%%)
  171.             ChlorinePos!(N%%, M%%) = ChlorinePos!(N%%, M%%) + ChlorineVel!(N%%, M%%)
  172.             SodiumVel!(N%%, M%%) = SodiumVel!(N%%, M%%) + SodiumAcc!(N%%, M%%)
  173.             IF ABS(SodiumVel!(N%%, M%%)) > Kelvin! THEN SodiumVel!(N%%, M%%) = Kelvin! * (ABS(SodiumVel!(N%%, M%%)) / SodiumVel!(N%%, M%%))
  174.             ChlorineVel!(N%%, M%%) = ChlorineVel!(N%%, M%%) + ChlorineAcc!(N%%, M%%)
  175.             IF ABS(ChlorineVel!(N%%, M%%)) > Kelvin! THEN ChlorineVel!(N%%, M%%) = Kelvin! * (ABS(ChlorineVel!(N%%, M%%)) / ChlorineVel!(N%%, M%%))
  176.         NEXT M%%
  177.     NEXT N%%
  178.     Theta! = Theta! + 0.008
  179.     IF Theta! > _PI THEN Theta! = Theta! - 2 * _PI
  180.     Count% = Count% + 1
  181.     IF (Generate` OR Count% = 300) AND NoBalls%% < TotBalls% THEN
  182.         NoBalls%% = NoBalls%% + 1
  183.         Generate` = False        
  184.     END IF
  185.     IF Count% = 300 THEN Count% = 0
  186.     LOCATE 1, 1: PRINT NoBalls%%;
  187.     _DISPLAY
  188.  
  189.  
  190. FUNCTION Attraction! (Dist!)
  191.     Attraction! = A0! * (1 / (Dist! / A2!) ^ A1!)
  192.  
  193. FUNCTION Repulsion! (Dist!)
  194.     Repulsion! = -R0! * (1 / (Dist! / R2!) ^ R1!)
  195.  
  196. FUNCTION XDash! (X!, Z!)
  197.     XDash! = X! * COS(Theta!) + Z! * SIN(Theta!)
  198.  
  199. FUNCTION ZDash! (X!, Z!)
  200.     ZDash! = -X! * SIN(Theta!) + Z! * COS(Theta!)
  201.  
  202. SUB CentreOfMass 'fio centre of mass adjustment & zero net momentums
  203.     TotMass# = 0
  204.     MRx# = 0: MRy# = 0: MRz# = 0
  205.     Px# = 0: Py# = 0: Pz# = 0
  206.     FOR N% = 0 TO TotBalls%% - 1
  207.         TotMass# = TotMass# + 1
  208.         MRx# = MRx# + SodiumPos!(N%, 0)
  209.         MRy# = MRy# + SodiumPos!(N%, 1)
  210.         MRz# = MRz# + SodiumPos!(N%, 2)
  211.         Px# = SodiumVel!(N%, 0) + Px#
  212.         Py# = SodiumVel!(N%, 1) + Py#
  213.         Pz# = SodiumVel!(N%, 2) + Pz#
  214.         TotMass# = TotMass# + 1
  215.         MRx# = MRx# + ChlorinePos!(N%, 0)
  216.         MRy# = MRy# + ChlorinePos!(N%, 1)
  217.         MRz# = MRz# + ChlorinePos!(N%, 2)
  218.         Px# = ChlorineVel!(N%, 0) + Px#
  219.         Py# = ChlorineVel!(N%, 1) + Py#
  220.         Pz# = ChlorineVel!(N%, 2) + Pz#
  221.     NEXT N%
  222.     FOR N% = 0 TO TotBalls%% - 1
  223.         SodiumPos!(N%, 0) = SodiumPos!(N%, 0) - (MRx# / TotMass#)
  224.         SodiumPos!(N%, 1) = SodiumPos!(N%, 1) - (MRy# / TotMass#)
  225.         SodiumPos!(N%, 2) = SodiumPos!(N%, 2) - (MRz# / TotMass#)
  226.         SodiumVel!(N%, 0) = SodiumVel!(N%, 0) - (Px# / TotMass#)
  227.         SodiumVel!(N%, 1) = SodiumVel!(N%, 1) - (Py# / TotMass#)
  228.         SodiumVel!(N%, 2) = SodiumVel!(N%, 2) - (Pz# / TotMass#)
  229.         ChlorinePos!(N%, 0) = ChlorinePos!(N%, 0) - (MRx# / TotMass#)
  230.         ChlorinePos!(N%, 1) = ChlorinePos!(N%, 1) - (MRy# / TotMass#)
  231.         ChlorinePos!(N%, 2) = ChlorinePos!(N%, 2) - (MRz# / TotMass#)
  232.         ChlorineVel!(N%, 0) = ChlorineVel!(N%, 0) - (Px# / TotMass#)
  233.         ChlorineVel!(N%, 1) = ChlorineVel!(N%, 1) - (Py# / TotMass#)
  234.         ChlorineVel!(N%, 2) = ChlorineVel!(N%, 2) - (Pz# / TotMass#)
  235.     NEXT N%
  236.  
« Last Edit: November 18, 2018, 07:22:40 am by Qwerkey »

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Sodium Chloride
« Reply #21 on: November 18, 2018, 05:04:32 am »
Here is version 5.  In this probably final version, Na Cl pairs are gradually introduced.  The forces are adjusted so that there is a preferential attraction at each sodium ion for chlorines at the six orthogonal positions.  In the model, these directions are aligned with the grid x-, y-, and z- axes (even though there is viewing rotation around the y- axis).  In reality, of course, there is no such directional preference, but I could not fathom the mathematics for 3-dimensional individual atom axes rotations.

The model does lead to a final arrangement into some sort of cubic structure (you will have to let it run for some time after the final quantity, 125, is reached).  If we had a crystallographer, he or she might be able to say what sort of structure it is or even if the final structure is always the same.
Code: QB64: [Select]
  1. 'Simple Model of Ionic Crystal v5 by QWERKEY 2018-11-18
  2.  
  3. CONST True = -1`, False = 0`
  4. CONST A0! = 100, A1! = 2, R0! = 250, R1! = 2.3, A2! = 200, R2! = 115, FMin! = -5 '-55
  5. CONST TotBalls%% = 125, Atom! = 110, Kelvin! = 0.35, F1! = 1000, F2! = 3000, Xstal! = 0.98
  6. CONST ChlorineSize%% = 35, SodiumSize%% = 25, Offset% = 730, ScreenX% = 1260, ScreenY% = 800, ThetaMax! = 0.5
  7.  
  8. DIM SHARED SodiumPos!(TotBalls%% - 1, 2), ChlorinePos!(TotBalls%% - 1, 2), NoBalls%%
  9. DIM SHARED SodiumVel!(TotBalls%% - 1, 2), ChlorineVel!(TotBalls%% - 1, 2), ViewAngle!
  10. DIM SodiumAcc!(TotBalls%% - 1, 2), ChlorineAcc!(TotBalls%% - 1, 2), BallStats%(1, 2)
  11.  
  12. _TITLE "Very Accurate Quantum Physics Model"
  13.  
  14. FOR N%% = 0 TO TotBalls%% - 1
  15.     FOR M%% = 0 TO 2
  16.         IF N%% = 0 THEN
  17.             ChlorinePos!(N%%, M%%) = Atom! * (RND - 0.5)
  18.         ELSE
  19.             ChlorinePos!(N%%, M%%) = Atom! * (1 + (RND * (1 + (N%% / TotBalls%%))))
  20.             IF RND > 0.5 THEN ChlorinePos!(N%%, M%%) = -ChlorinePos!(N%%, M%%)
  21.         END IF
  22.         ChlorineVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  23.         SodiumVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  24.     NEXT M%%
  25.     Chi! = 2 * _PI * RND
  26.     Psi! = _PI * RND
  27.     SodiumPos!(N%%, 2) = ChlorinePos!(N%%, 2) + Atom! * SIN(Psi!) * COS(Chi!)
  28.     SodiumPos!(N%%, 0) = ChlorinePos!(N%%, 0) + Atom! * SIN(Psi!) * SIN(Chi!)
  29.     SodiumPos!(N%%, 1) = ChlorinePos!(N%%, 1) + Atom! * COS(Psi!)
  30. NEXT N%%
  31.  
  32. ' Ball Colours (Cyperium Method)
  33. DATA 0,0,255
  34. DATA 255,0,0
  35. FOR N%% = 0 TO 1
  36.     FOR P%% = 0 TO 2
  37.         READ BallStats%(N%%, P%%)
  38.     NEXT P%%
  39.     TempImage& = _NEWIMAGE(256, 256, 32)
  40.     _DEST TempImage&
  41.     COLOR _RGBA(BallStats%(N%%, 0), BallStats%(N%%, 1), BallStats%(N%%, 2), 65), _RGBA(0, 0, 0, 0)
  42.     'Image data goes from 1 to 255 (not 0 to 255)
  43.     FOR Z% = 128 TO 255
  44.         FOR X% = 1 TO 255
  45.             FOR Y% = 1 TO 255
  46.                 DeltaX% = X% - 127
  47.                 DeltaY% = Y% - 127
  48.                 DeltaZ% = Z% - 127
  49.                 Dist! = SQR((DeltaX% * DeltaX%) + (DeltaY% * DeltaY%) + (DeltaZ% * DeltaZ%))
  50.                 IF Dist! > 125 AND Dist! < 127 THEN PSET (X%, Y%), _RGBA(CINT(Z% * BallStats%(N%%, 0) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 1) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 2) * (1 - (XBright! * X% / 255)) / 255), 65)
  51.             NEXT
  52.         NEXT
  53.     NEXT
  54.     IF N%% = 0 THEN
  55.         Sodium& = _COPYIMAGE(TempImage&, 33)
  56.     ELSE
  57.         Chlorine& = _COPYIMAGE(TempImage&, 33)
  58.     END IF
  59.     _FREEIMAGE TempImage&
  60. NEXT N%%
  61.  
  62. TempImage& = _NEWIMAGE(102, 2, 32)
  63. _DEST TempImage&
  64. LINE (0, 0)-(101, 1), _RGB32(255, 255, 255), BF
  65. LineImage& = _COPYIMAGE(TempImage&, 33)
  66. _FREEIMAGE TempImage&
  67.  
  68. 'Create screen
  69. SCREEN _NEWIMAGE(ScreenX%, ScreenY%, 32)
  70. _DISPLAYORDER _HARDWARE , _SOFTWARE 'do not even render the software layer, just the hardware one.
  71.  
  72. NoBalls%% = 2
  73. Generate` = False
  74. Count% = 0
  75.     _LIMIT 25
  76.     '_LIMIT 5
  77.     CALL CentreOfMass
  78.     MaxDist! = 0
  79.     FOR N%% = 0 TO NoBalls%% - 1
  80.         XTemp! = XDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2))): ZTemp! = ZDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2)))
  81.         _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Chlorine& TO(-(ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  82.         _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Chlorine& TO((ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  83.         XTemp! = XDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2))): ZTemp! = ZDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2)))
  84.         _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Sodium& TO(-(SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  85.         _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Sodium& TO((SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  86.         FOR M%% = 0 TO 2
  87.             SodiumAcc!(N%%, M%%) = 0
  88.         NEXT M%%
  89.         FOR M%% = 0 TO 2
  90.             ChlorineAcc!(N%%, M%%) = 0
  91.         NEXT M%%
  92.         FOR L%% = 0 TO NoBalls%% - 1
  93.             'opposites
  94.             D! = SQR((SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  95.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  96.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  97.             FOR M%% = 0 TO 2
  98.                 SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  99.             NEXT M%%
  100.             IF D! < Atom! THEN
  101.                 IF N%% = NoBalls%% - 1 AND L%% < N%% AND NOT Generate` THEN
  102.                     Generate` = True
  103.                 END IF
  104.             END IF
  105.             D! = SQR((SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) * (SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) + (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) * (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) + (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)) * (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)))
  106.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  107.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  108.             FOR M%% = 0 TO 2
  109.                 ChlorineAcc!(N%%, M%%) = F! * (SodiumPos!(L%%, M%%) - ChlorinePos!(N%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  110.             NEXT M%%
  111.             '!!! Might change the generation routine, as well
  112.             IF D! < Atom! THEN
  113.                 IF N%% = NoBalls%% - 1 AND L%% < N%% AND NOT Generate` THEN
  114.                     Generate` = True
  115.                 END IF
  116.             END IF
  117.             IF L%% <> N%% THEN
  118.                 'same type
  119.                 D! = SQR((SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) * (SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) + (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) * (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) + (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)) * (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)))
  120.                 F! = -(Attraction!(D!)) / F2!
  121.                 FOR M%% = 0 TO 2
  122.                     SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - SodiumPos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  123.                 NEXT M%%
  124.                 D! = SQR((ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  125.                 F! = -(Attraction!(D!)) / F2!
  126.                 FOR M%% = 0 TO 2
  127.                     ChlorineAcc!(N%%, M%%) = -F! * (ChlorinePos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  128.                 NEXT M%%
  129.             END IF
  130.         NEXT L%%
  131.         FOR M%% = 0 TO 2
  132.             SodiumPos!(N%%, M%%) = SodiumPos!(N%%, M%%) + SodiumVel!(N%%, M%%)
  133.             ChlorinePos!(N%%, M%%) = ChlorinePos!(N%%, M%%) + ChlorineVel!(N%%, M%%)
  134.             SodiumVel!(N%%, M%%) = SodiumVel!(N%%, M%%) + SodiumAcc!(N%%, M%%)
  135.             IF ABS(SodiumVel!(N%%, M%%)) > Kelvin! THEN SodiumVel!(N%%, M%%) = Kelvin! * (ABS(SodiumVel!(N%%, M%%)) / SodiumVel!(N%%, M%%))
  136.             ChlorineVel!(N%%, M%%) = ChlorineVel!(N%%, M%%) + ChlorineAcc!(N%%, M%%)
  137.             IF ABS(ChlorineVel!(N%%, M%%)) > Kelvin! THEN ChlorineVel!(N%%, M%%) = Kelvin! * (ABS(ChlorineVel!(N%%, M%%)) / ChlorineVel!(N%%, M%%))
  138.         NEXT M%%
  139.     NEXT N%%
  140.     FOR N%% = 0 TO NoBalls%% - 1
  141.         FOR M%% = 0 TO 5 'the six orthogonal positions from each sodium atom
  142.             CALL Orthogonal(N%%, M%%) 'Move chlorine atom
  143.         NEXT M%%
  144.     NEXT N%%
  145.     ViewAngle! = ViewAngle! + 0.008
  146.     IF ViewAngle! > _PI THEN ViewAngle! = ViewAngle! - 2 * _PI
  147.     Count% = Count% + 1
  148.     IF (Generate` OR Count% = 300) AND NoBalls%% < TotBalls% THEN
  149.         'IF Generate` AND NoBalls%% < TotBalls% THEN
  150.         NoBalls%% = NoBalls%% + 1
  151.         Generate` = False
  152.     END IF
  153.     IF Count% = 300 THEN Count% = 0
  154.     LOCATE 1, 1: PRINT NoBalls%%;
  155.     _DISPLAY
  156.  
  157.  
  158. FUNCTION Attraction! (Dist!)
  159.     Attraction! = A0! * (1 / (Dist! / A2!) ^ A1!)
  160.  
  161. FUNCTION Repulsion! (Dist!)
  162.     Repulsion! = -R0! * (1 / (Dist! / R2!) ^ R1!)
  163.  
  164. FUNCTION XDash! (X!, Z!)
  165.     XDash! = X! * COS(ViewAngle!) + Z! * SIN(ViewAngle!)
  166.  
  167. FUNCTION ZDash! (X!, Z!)
  168.     ZDash! = -X! * SIN(ViewAngle!) + Z! * COS(ViewAngle!)
  169.  
  170. SUB Orthogonal (P%%, Q%%)
  171.     OnlyOneChlorine%% = True
  172.     NoChlorines%% = 0
  173.     R%% = 0
  174.     WHILE R%% <= NoBalls%% - 1 AND OnlyOneChlorine%%
  175.         IF R%% <> P%% THEN
  176.             Sepn! = SQR((SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)) * (SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)) + (SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)) * (SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)) + (SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)) * (SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)))
  177.             IF Sepn! < Atom! THEN
  178.                 X! = SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)
  179.                 Y! = SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)
  180.                 Z! = SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)
  181.                 SELECT CASE Q%%
  182.                     CASE 0
  183.                         S1! = SQR(Y! * Y! + Z! * Z!)
  184.                         Theta! = _ATAN2(S1!, X!)
  185.                         IF X! > 0 AND X! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  186.                     CASE 1
  187.                         S1! = SQR(X! * X! + Z! * Z!)
  188.                         Theta! = _ATAN2(S1!, Y!)
  189.                         IF Y! > 0 AND Y! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  190.                     CASE 2
  191.                         S1! = SQR(Y! * Y! + X! * X!)
  192.                         Theta! = _ATAN2(S1!, Z!)
  193.                         IF Z! > 0 AND Z! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  194.                     CASE 3
  195.                         S1! = SQR(Y! * Y! + Z! * Z!)
  196.                         Theta! = _ATAN2(S1!, -X!)
  197.                         IF X! < 0 AND X! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  198.                     CASE 4
  199.                         S1! = SQR(X! * X! + Z! * Z!)
  200.                         Theta! = _ATAN2(S1!, -Y!)
  201.                         IF Y! < 0 AND Y! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  202.                     CASE ELSE '5
  203.                         S1! = SQR(Y! * Y! + X! * X!)
  204.                         Theta! = _ATAN2(S1!, -Z!)
  205.                         IF Z! < 0 AND Z! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  206.                 END SELECT
  207.             END IF
  208.         END IF
  209.         IF OnlyOneChlorine%% THEN
  210.             Sepn! = SQR((ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)) * (ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)) + (ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)) * (ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)) + (ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)) * (ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)))
  211.             IF Sepn! < Atom! THEN
  212.                 X! = ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)
  213.                 Y! = ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)
  214.                 Z! = ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)
  215.                 SELECT CASE Q%%
  216.                     CASE 0
  217.                         S1! = SQR(Y! * Y! + Z! * Z!)
  218.                         Theta! = _ATAN2(S1!, X!)
  219.                         IF X! > 0 AND X! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  220.                             NoChlorines%% = NoChlorines%% + 1
  221.                             ROne%% = R%%
  222.                         END IF
  223.                     CASE 1
  224.                         S1! = SQR(X! * X! + Z! * Z!)
  225.                         Theta! = _ATAN2(S1!, Y!)
  226.                         IF Y! > 0 AND Y! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  227.                             NoChlorines%% = NoChlorines%% + 1
  228.                             ROne%% = R%%
  229.                         END IF
  230.                     CASE 2
  231.                         S1! = SQR(Y! * Y! + X! * X!)
  232.                         Theta! = _ATAN2(S1!, Z!)
  233.                         IF Z! > 0 AND Z! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  234.                             NoChlorines%% = NoChlorines%% + 1
  235.                             ROne%% = R%%
  236.                         END IF
  237.                     CASE 3
  238.                         S1! = SQR(Y! * Y! + Z! * Z!)
  239.                         Theta! = _ATAN2(S1!, -X!)
  240.                         IF X! < 0 AND X! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  241.                             NoChlorines%% = NoChlorines%% + 1
  242.                             ROne%% = R%%
  243.                         END IF
  244.                     CASE 4
  245.                         S1! = SQR(X! * X! + Z! * Z!)
  246.                         Theta! = _ATAN2(S1!, -Y!)
  247.                         IF Y! < 0 AND Y! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  248.                             NoChlorines%% = NoChlorines%% + 1
  249.                             ROne%% = R%%
  250.                         END IF
  251.                     CASE ELSE '5
  252.                         S1! = SQR(Y! * Y! + X! * X!)
  253.                         Theta! = _ATAN2(S1!, -Z!)
  254.                         IF Z! < 0 AND Z! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  255.                             NoChlorines%% = NoChlorines%% + 1
  256.                             ROne%% = R%%
  257.                         END IF
  258.                 END SELECT
  259.                 IF NoChlorines%% > 1 THEN OnlyOneChlorine%% = False
  260.             END IF
  261.         END IF
  262.         R%% = R%% + 1
  263.     WEND
  264.     IF NoChlorines%% = 0 THEN OnlyOneChlorine%% = False
  265.  
  266.     IF OnlyOneChlorine%% THEN
  267.  
  268.         'LOCATE 2, 1
  269.         'PRINT P%%, Q%%, ROne%%
  270.         ''FOR A%% = 0 TO NoBalls%% - 1
  271.         ''    FOR B%% = 0 TO 2
  272.         ''        PRINT A%%, B%%, SodiumPos!(A%%, B%%), ChlorinePos!(A%%, B%%)
  273.         ''    NEXT B%%
  274.         ''NEXT A%%
  275.         'END
  276.         'R%% = R%% - 1
  277.  
  278.         'Move Chlorine Atom
  279.         X! = ChlorinePos!(ROne%%, 0) - SodiumPos!(P%%, 0)
  280.         Y! = ChlorinePos!(ROne%%, 1) - SodiumPos!(P%%, 1)
  281.         Z! = ChlorinePos!(ROne%%, 2) - SodiumPos!(P%%, 2)
  282.         SELECT CASE Q%%
  283.             CASE 0, 3
  284.                 ChlorinePos!(ROne%%, 1) = ChlorinePos!(ROne%%, 1) - Y! * (1 - Xstal!)
  285.                 ChlorinePos!(ROne%%, 2) = ChlorinePos!(ROne%%, 2) - Z! * (1 - Xstal!)
  286.             CASE 1, 4
  287.                 ChlorinePos!(ROne%%, 0) = ChlorinePos!(ROne%%, 0) - X! * (1 - Xstal!)
  288.                 ChlorinePos!(ROne%%, 2) = ChlorinePos!(ROne%%, 2) - Z! * (1 - Xstal!)
  289.             CASE 2, 5
  290.                 ChlorinePos!(ROne%%, 0) = ChlorinePos!(ROne%%, 0) - X! * (1 - Xstal!)
  291.                 ChlorinePos!(ROne%%, 1) = ChlorinePos!(ROne%%, 1) - Y! * (1 - Xstal!)
  292.         END SELECT
  293.     END IF
  294.  
  295.  
  296. SUB CentreOfMass 'fio centre of mass adjustment & zero net momentums
  297.     TotMass# = 0
  298.     MRx# = 0: MRy# = 0: MRz# = 0
  299.     Px# = 0: Py# = 0: Pz# = 0
  300.     FOR N% = 0 TO TotBalls%% - 1
  301.         TotMass# = TotMass# + 1
  302.         MRx# = MRx# + SodiumPos!(N%, 0)
  303.         MRy# = MRy# + SodiumPos!(N%, 1)
  304.         MRz# = MRz# + SodiumPos!(N%, 2)
  305.         Px# = SodiumVel!(N%, 0) + Px#
  306.         Py# = SodiumVel!(N%, 1) + Py#
  307.         Pz# = SodiumVel!(N%, 2) + Pz#
  308.         TotMass# = TotMass# + 1
  309.         MRx# = MRx# + ChlorinePos!(N%, 0)
  310.         MRy# = MRy# + ChlorinePos!(N%, 1)
  311.         MRz# = MRz# + ChlorinePos!(N%, 2)
  312.         Px# = ChlorineVel!(N%, 0) + Px#
  313.         Py# = ChlorineVel!(N%, 1) + Py#
  314.         Pz# = ChlorineVel!(N%, 2) + Pz#
  315.     NEXT N%
  316.     FOR N% = 0 TO TotBalls%% - 1
  317.         SodiumPos!(N%, 0) = SodiumPos!(N%, 0) - (MRx# / TotMass#)
  318.         SodiumPos!(N%, 1) = SodiumPos!(N%, 1) - (MRy# / TotMass#)
  319.         SodiumPos!(N%, 2) = SodiumPos!(N%, 2) - (MRz# / TotMass#)
  320.         SodiumVel!(N%, 0) = SodiumVel!(N%, 0) - (Px# / TotMass#)
  321.         SodiumVel!(N%, 1) = SodiumVel!(N%, 1) - (Py# / TotMass#)
  322.         SodiumVel!(N%, 2) = SodiumVel!(N%, 2) - (Pz# / TotMass#)
  323.         ChlorinePos!(N%, 0) = ChlorinePos!(N%, 0) - (MRx# / TotMass#)
  324.         ChlorinePos!(N%, 1) = ChlorinePos!(N%, 1) - (MRy# / TotMass#)
  325.         ChlorinePos!(N%, 2) = ChlorinePos!(N%, 2) - (MRz# / TotMass#)
  326.         ChlorineVel!(N%, 0) = ChlorineVel!(N%, 0) - (Px# / TotMass#)
  327.         ChlorineVel!(N%, 1) = ChlorineVel!(N%, 1) - (Py# / TotMass#)
  328.         ChlorineVel!(N%, 2) = ChlorineVel!(N%, 2) - (Pz# / TotMass#)
  329.     NEXT N%
  330.  
« Last Edit: November 18, 2018, 07:23:05 am by Qwerkey »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
Re: Sodium Chloride
« Reply #22 on: November 18, 2018, 07:50:05 am »
Marvelous. I let it run for 45 minutes, starting at about half that time, and the crystal grew nice and naturally. Love it.

Say, this leads us to the next phase, right? Start with a perfect crystal, and the displace one of the atoms real quick. The pattern that spreads will be a classic phonon. (Something tells me Qwerkey already knows this is not a misspelling of phoTon.)

Back when taking physics 700-something, a Russian professor had us derive the quantum theory of phonons for an exam, from memory, as a surprise. He used his red pen once on my last page:

http://www.barnesreport.net/scripturam/solid%20state%20physics/Quantum%20Theory%20of%20Phonons.pdf
« Last Edit: November 18, 2018, 07:51:31 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Sodium Chloride
« Reply #23 on: November 18, 2018, 10:36:49 am »
This leads us to the next phase, right? Start with a perfect crystal, and the displace one of the atoms real quick. The pattern that spreads will be a classic phonon.

Hmm! So our next post will be entitled "Quantum Modelling of Phonon Propagation in the Sodium Chloride Crystal"?  Ambitious!  It would, any at rate, be interesting to see how long it would take Pete to get his irritatingly incessant politics into that.
« Last Edit: November 18, 2018, 10:41:06 am by Qwerkey »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Sodium Chloride
« Reply #24 on: November 18, 2018, 10:56:26 am »
This leads us to the next phase, right? Start with a perfect crystal, and the displace one of the atoms real quick. The pattern that spreads will be a classic phonon.

Hmm! So our next post will be entitled "Quantum Modelling of Phonon Propagation in the Sodium Chloride Crystal"?  Ambitious!  It would, any at rate, be interesting to see how long it would take Pete to get his irritatingly incessant politics into that.

Q-Mop Piscc -- Isn't that what illegal immigrates have to do after a Democrat goes to the restroom?  And get underpaid while doing it to boot!

(Ha!  I beat Pete to it.)  ;D

************************

Got to admit, I'm enjoying these little demos.  I'll be happy to watch you Q-Mop Piscc when you do it.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Sodium Chloride
« Reply #25 on: November 18, 2018, 11:22:42 am »
This leads us to the next phase, right? Start with a perfect crystal, and the displace one of the atoms real quick. The pattern that spreads will be a classic phonon.

Hmm! So our next post will be entitled "Quantum Modelling of Phonon Propagation in the Sodium Chloride Crystal"?  Ambitious!  It would, any at rate, be interesting to see how long it would take Pete to get his irritatingly incessant politics into that.

Faster than the separation of of bromide from sodium. That's a long and complicated process, but eventually it can be achieved. I believe it's called a BR-exit.

As for the next version, might I suggest a time lapse version? In other words allow the use of key presses to speed the simulation up. You did a great job of achieving the more traditional and expected cubic crystalline formation, but it's a bit like watching grass grow. I also miss the effects a previous version that produced interactions with white straight lines between the atoms. Why did you decide to remove those? Also, when new molecules join from off the screen, the effect is perfect, but when they appear on the screen, they start out too large, which makes them look more like they just magically appeared, instead of a far away object coming into visual range. I don't know if you'd want to bother tweaking that or not for any further versions, but kudos for making an original program contribution.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Re: Sodium Chloride
« Reply #26 on: November 23, 2018, 05:04:45 am »
I said that the previous version would be the last - everyone must be fed up with coloured discs moving about the screen, but STxAxTIC & Pete's ideas/suggestions were worthy of note.  So this is the final final version.

Here the program starts with a number of atoms as a seed crystal and then further molecules (atom pairs) are added from outside.  You have the options to draw the bonds and to pause the process.

The program starts with a seed of NaCl atoms in a face-centred cubic crystal with spacings set at the correct final value.  I therefore expected this to be stable and await the addition of the further atoms.  However, you will see the program immediately breaks up this crystal and reforms the atoms into a different crystal arrangement.  You'd have thought that as I am the program creator, I'd be able to get this right, but I suspect that this demonstrates my poor understanding of crystallography.  It takes about 80 seconds for the crystal to reform.

It then takes about 12 minutes for the additional atoms to arrive and be added to the crystal.  The new atoms are different colours (red & blue for seed atoms, pink & cyan for the new ones).  The colour difference is only to show which are the new ones.  They all behave exactly the same.  Some of the new ones may actually end up deeper in the crystal than the original ones.  This shows that the structure is a little fluid.  In reality, this would hardly ever occur as the quantum bonds are very strong.

Code: QB64: [Select]
  1. 'Simple Model of Ionic Crystal v6 by QWERKEY 2018-11-23
  2.  
  3. CONST True = -1`, False = 0`
  4. CONST A0! = 100, A1! = 2, R0! = 250, R1! = 2.3, A2! = 200, R2! = 115, F2! = 3000, FMin! = -5 '-55
  5. CONST TotBalls%% = 125, NoSeed%% = 75, Atom! = 110, Xstal! = 0.98, Kelvin! = 0.35
  6. CONST ChlorineSize%% = 35, SodiumSize%% = 25, Offset% = 730, ScreenX% = 1260, ScreenY% = 800, ThetaMax! = 0.5
  7.  
  8. DIM SHARED SodiumPos!(TotBalls%% - 1, 2), ChlorinePos!(TotBalls%% - 1, 2), NoBalls%%
  9. DIM SHARED SodiumVel!(TotBalls%% - 1, 2), ChlorineVel!(TotBalls%% - 1, 2), ViewAngle!
  10. DIM SodiumAcc!(TotBalls%% - 1, 2), ChlorineAcc!(TotBalls%% - 1, 2), BallStats%(3, 2)
  11.  
  12. _TITLE "Very Accurate Quantum Physics Model"
  13.  
  14. 'Set Seed Crystal
  15. Default! = 0.69 * Atom!
  16. FOR I%% = -2 TO 2
  17.     FOR J%% = -2 TO 2
  18.         FOR K%% = -1 TO 1
  19.             IF J%% \ 2 <> J%% / 1 THEN
  20.                 ChlorinePos!(N%%, 0) = Default! * I%%
  21.                 ChlorinePos!(N%%, 1) = Default! * J%%
  22.                 ChlorinePos!(N%%, 2) = 2 * Default! * K%%
  23.                 SodiumPos!(N%%, 0) = ChlorinePos!(N%%, 0)
  24.                 SodiumPos!(N%%, 1) = ChlorinePos!(N%%, 1)
  25.                 SodiumPos!(N%%, 2) = ChlorinePos!(N%%, 2) - Default!
  26.             ELSE
  27.                 ChlorinePos!(N%%, 0) = Default! * I%%
  28.                 ChlorinePos!(N%%, 1) = Default! * J%%
  29.                 ChlorinePos!(N%%, 2) = 2 * Default! * K%% - Default!
  30.                 SodiumPos!(N%%, 0) = ChlorinePos!(N%%, 0)
  31.                 SodiumPos!(N%%, 1) = ChlorinePos!(N%%, 1)
  32.                 SodiumPos!(N%%, 2) = ChlorinePos!(N%%, 2) + Default!
  33.             END IF
  34.             N%% = N%% + 1
  35.         NEXT K%%
  36.     NEXT J%%
  37. NEXT I%%
  38. FOR N%% = 0 TO NoSeed%% - 1
  39.     FOR M%% = 0 TO 2
  40.         ChlorineVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  41.         SodiumVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  42.     NEXT M%%
  43. NEXT N%%
  44. 'Additional atom properties
  45. FOR N%% = NoSeed% TO TotBalls%% - 1
  46.     Xi! = RND * _PI / 4 '0.5
  47.     ChlorinePos!(N%%, 0) = (1 + 0.75 * RND) * ScreenX% / 3
  48.     IF RND > 0.5 THEN ChlorinePos!(N%%, 0) = ChlorinePos!(N%%, 0) * -1
  49.     Chi! = 2 * _PI * RND
  50.     RPosn! = ChlorinePos!(N%%, 0) * TAN(Xi!)
  51.     ChlorinePos!(N%%, 1) = RPosn! * SIN(Chi!)
  52.     ChlorinePos!(N%%, 2) = RPosn! * COS(Chi!)
  53.     FOR M%% = 0 TO 2
  54.         IF RND > 0.5 THEN ChlorinePos!(N%%, M%%) = -ChlorinePos!(N%%, M%%)
  55.         ChlorineVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  56.         SodiumVel!(N%%, M%%) = (RND - 0.5) * Kelvin!
  57.     NEXT M%%
  58.     Chi! = 2 * _PI * RND
  59.     Psi! = _PI * RND
  60.     SodiumPos!(N%%, 2) = ChlorinePos!(N%%, 2) + Atom! * SIN(Psi!) * COS(Chi!)
  61.     SodiumPos!(N%%, 0) = ChlorinePos!(N%%, 0) + Atom! * SIN(Psi!) * SIN(Chi!)
  62.     SodiumPos!(N%%, 1) = ChlorinePos!(N%%, 1) + Atom! * COS(Psi!)
  63. NEXT N%%
  64.  
  65. ' Ball Colours (Cyperium Method)
  66. DATA 0,0,255
  67. DATA 255,0,0
  68. DATA 217,163,173
  69. DATA 0,200,200
  70. FOR N%% = 0 TO 3
  71.     FOR P%% = 0 TO 2
  72.         READ BallStats%(N%%, P%%)
  73.     NEXT P%%
  74.     TempImage& = _NEWIMAGE(256, 256, 32)
  75.     _DEST TempImage&
  76.     COLOR _RGBA(BallStats%(N%%, 0), BallStats%(N%%, 1), BallStats%(N%%, 2), 65), _RGBA(0, 0, 0, 0)
  77.     'Image data goes from 1 to 255 (not 0 to 255)
  78.     FOR Z% = 128 TO 255
  79.         FOR X% = 1 TO 255
  80.             FOR Y% = 1 TO 255
  81.                 DeltaX% = X% - 127
  82.                 DeltaY% = Y% - 127
  83.                 DeltaZ% = Z% - 127
  84.                 Dist! = SQR((DeltaX% * DeltaX%) + (DeltaY% * DeltaY%) + (DeltaZ% * DeltaZ%))
  85.                 IF Dist! > 125 AND Dist! < 127 THEN PSET (X%, Y%), _RGBA(CINT(Z% * BallStats%(N%%, 0) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 1) * (1 - (XBright! * X% / 255)) / 255), CINT(Z% * BallStats%(N%%, 2) * (1 - (XBright! * X% / 255)) / 255), 65)
  86.             NEXT
  87.         NEXT
  88.     NEXT
  89.     IF N%% = 0 THEN
  90.         Sodium& = _COPYIMAGE(TempImage&, 33)
  91.     ELSEIF N%% = 1 THEN
  92.         Chlorine& = _COPYIMAGE(TempImage&, 33)
  93.     ELSEIF N%% = 2 THEN
  94.         Pink& = _COPYIMAGE(TempImage&, 33)
  95.     ELSE
  96.         Cyan& = _COPYIMAGE(TempImage&, 33)
  97.     END IF
  98.     _FREEIMAGE TempImage&
  99. NEXT N%%
  100.  
  101. 'Images
  102. TempImage& = _NEWIMAGE(102, 52, 32)
  103. _DEST TempImage&
  104. LINE (0, 0)-(101, 51), _RGB32(255, 255, 255), BF
  105. LineImage& = _COPYIMAGE(TempImage&, 33)
  106. _FREEIMAGE TempImage&
  107. TempImage& = _NEWIMAGE(80, 100, 32)
  108. _DEST TempImage&
  109. COLOR _RGB32(150, 150, 150), _RGB32(80, 80, 80)
  110. _PRINTSTRING (20, 40), "Pause"
  111. Pause& = _COPYIMAGE(TempImage&, 33)
  112. _FREEIMAGE TempImage&
  113. TempImage& = _NEWIMAGE(80, 100, 32)
  114. _DEST TempImage&
  115. COLOR _RGB32(150, 150, 150), _RGB32(80, 80, 80)
  116. _PRINTSTRING (8, 40), "Continue"
  117. Continue& = _COPYIMAGE(TempImage&, 33)
  118. _FREEIMAGE TempImage&
  119. TempImage& = _NEWIMAGE(80, 100, 32)
  120. _DEST TempImage&
  121. COLOR _RGB32(150, 150, 150), _RGB32(80, 80, 80)
  122. _PRINTSTRING (20, 30), "Draw"
  123. _PRINTSTRING (20, 60), "Bonds"
  124. Bonds& = _COPYIMAGE(TempImage&, 33)
  125. _FREEIMAGE TempImage&
  126. TempImage& = _NEWIMAGE(80, 100, 32)
  127. _DEST TempImage&
  128. COLOR _RGB32(150, 150, 150), _RGB32(80, 80, 80)
  129. _PRINTSTRING (20, 25), "Don't"
  130. _PRINTSTRING (20, 45), "Draw"
  131. _PRINTSTRING (20, 65), "Bonds"
  132. NoBonds& = _COPYIMAGE(TempImage&, 33)
  133. _FREEIMAGE TempImage&
  134. TempImage& = _NEWIMAGE(80, 100, 32)
  135. _DEST TempImage&
  136. COLOR _RGB32(150, 150, 150), _RGB32(80, 80, 80)
  137. _PRINTSTRING (24, 40), "Quit"
  138. Quit& = _COPYIMAGE(TempImage&, 33)
  139.  
  140. 'Create screen
  141. SCREEN _NEWIMAGE(ScreenX%, ScreenY%, 32)
  142.  
  143. 'Run simulation
  144. NoBalls%% = NoSeed%%
  145. Count% = 0
  146. ViewAngle! = _PI * (1 - RND)
  147. DrawBonds` = False
  148. Paused` = False
  149. ASaltyDog` = True
  150. WHILE ASaltyDog`
  151.     _LIMIT 25
  152.     CALL CentreOfMass
  153.     'Mouse Input
  154.         XMouse% = _MOUSEX: YMouse% = _MOUSEY
  155.         IF _MOUSEBUTTON(1) THEN '2 for LH Mouse
  156.             IF XMouse% > ScreenX% - 199 AND XMouse% < ScreenX% - 121 AND YMouse% > 21 AND YMouse% < 119 THEN
  157.                 IF DrawBonds` THEN
  158.                     DrawBonds` = False
  159.                 ELSE
  160.                     DrawBonds` = True
  161.                 END IF
  162.             ELSEIF XMouse% > ScreenX% - 99 AND XMouse% < ScreenX% - 21 AND YMouse% > 21 AND YMouse% < 119 THEN
  163.                 IF Paused` THEN
  164.                     Paused` = False
  165.                 ELSE
  166.                     Paused` = True
  167.                 END IF
  168.             ELSEIF XMouse% > ScreenX% - 99 AND XMouse% < ScreenX% - 21 AND YMouse% > ScreenY% - 119 AND YMouse% < ScreenY% - 21 THEN
  169.                 ASaltyDog` = False
  170.             END IF
  171.         END IF
  172.     WEND
  173.     'Display atoms and calculate forces
  174.     MaxDist! = 0
  175.     F1! = 900 + 100 * ((NoBalls%% - NoSeed%%) / (TotBalls%% - NoSeed%%))
  176.     FOR N%% = 0 TO NoBalls%% - 1
  177.         XTemp! = XDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2))): ZTemp! = ZDash!((ChlorinePos!(N%%, 0)), (ChlorinePos!(N%%, 2)))
  178.         IF N%% <= NoSeed%% - 1 THEN
  179.             _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Chlorine& TO(-(ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  180.             _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Chlorine& TO((ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  181.         ELSE
  182.             _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Pink& TO(-(ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  183.             _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Pink& TO((ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-(-(ChlorineSize%% - 1) \ 2 + XTemp!, -(ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)-((ChlorineSize%% - 1) \ 2 + XTemp!, (ChlorineSize%% - 1) \ 2 + ChlorinePos!(N%%, 1), ZTemp! - Offset%)
  184.         END IF
  185.         XTemp! = XDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2))): ZTemp! = ZDash!((SodiumPos!(N%%, 0)), (SodiumPos!(N%%, 2)))
  186.         IF N%% <= NoSeed%% - 1 THEN
  187.             _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Sodium& TO(-(SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  188.             _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Sodium& TO((SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  189.         ELSE
  190.             _MAPTRIANGLE (0, 0)-(255, 0)-(0, 255), Cyan& TO(-(SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  191.             _MAPTRIANGLE (255, 255)-(0, 255)-(255, 0), Cyan& TO((SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-(-(SodiumSize%% - 1) \ 2 + XTemp!, -(SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)-((SodiumSize%% - 1) \ 2 + XTemp!, (SodiumSize%% - 1) \ 2 + SodiumPos!(N%%, 1), ZTemp! - Offset%)
  192.         END IF
  193.         FOR M%% = 0 TO 2
  194.             SodiumAcc!(N%%, M%%) = 0
  195.         NEXT M%%
  196.         FOR M%% = 0 TO 2
  197.             ChlorineAcc!(N%%, M%%) = 0
  198.         NEXT M%%
  199.         FOR L%% = 0 TO NoBalls%% - 1
  200.             'opposites
  201.             D! = SQR((SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (SodiumPos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (SodiumPos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (SodiumPos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  202.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  203.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  204.             FOR M%% = 0 TO 2
  205.                 SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  206.             NEXT M%%
  207.             IF D! < 0.9 * Atom! AND DrawBonds` THEN _MAPTRIANGLE (0, 0)-(101, 0)-(101, 51), LineImage& TO(XDash!(SodiumPos!(N%%, 0), SodiumPos!(N%%, 2)), SodiumPos!(N%%, 1), ZDash!(SodiumPos!(N%%, 0), SodiumPos!(N%%, 2)) - Offset%)-(XDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)), ChlorinePos!(L%%, 1), ZDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)) - Offset%)-(XDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)), ChlorinePos!(L%%, 1), ZDash!(ChlorinePos!(L%%, 0), ChlorinePos!(L%%, 2)) - Offset% - 1), , _SMOOTH
  208.             D! = SQR((SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) * (SodiumPos!(L%%, 0) - ChlorinePos!(N%%, 0)) + (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) * (SodiumPos!(L%%, 1) - ChlorinePos!(N%%, 1)) + (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)) * (SodiumPos!(L%%, 2) - ChlorinePos!(N%%, 2)))
  209.             F! = (Attraction!(D!) + Repulsion!(D!)) / F1!
  210.             'IF F! < FMin! / F1! THEN F! = FMin! / F1!
  211.             FOR M%% = 0 TO 2
  212.                 ChlorineAcc!(N%%, M%%) = F! * (SodiumPos!(L%%, M%%) - ChlorinePos!(N%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  213.             NEXT M%%
  214.             IF L%% <> N%% THEN
  215.                 'same type
  216.                 D! = SQR((SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) * (SodiumPos!(N%%, 0) - SodiumPos!(L%%, 0)) + (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) * (SodiumPos!(N%%, 1) - SodiumPos!(L%%, 1)) + (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)) * (SodiumPos!(N%%, 2) - SodiumPos!(L%%, 2)))
  217.                 F! = -(Attraction!(D!)) / F2!
  218.                 FOR M%% = 0 TO 2
  219.                     SodiumAcc!(N%%, M%%) = -F! * (SodiumPos!(N%%, M%%) - SodiumPos!(L%%, M%%)) / D! + SodiumAcc!(N%%, M%%)
  220.                 NEXT M%%
  221.                 D! = SQR((ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) * (ChlorinePos!(N%%, 0) - ChlorinePos!(L%%, 0)) + (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) * (ChlorinePos!(N%%, 1) - ChlorinePos!(L%%, 1)) + (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)) * (ChlorinePos!(N%%, 2) - ChlorinePos!(L%%, 2)))
  222.                 F! = -(Attraction!(D!)) / F2!
  223.                 FOR M%% = 0 TO 2
  224.                     ChlorineAcc!(N%%, M%%) = -F! * (ChlorinePos!(N%%, M%%) - ChlorinePos!(L%%, M%%)) / D! + ChlorineAcc!(N%%, M%%)
  225.                 NEXT M%%
  226.             END IF
  227.         NEXT L%%
  228.         'Pause
  229.         IF NOT Paused` THEN
  230.             FOR M%% = 0 TO 2
  231.                 SodiumPos!(N%%, M%%) = SodiumPos!(N%%, M%%) + SodiumVel!(N%%, M%%)
  232.                 ChlorinePos!(N%%, M%%) = ChlorinePos!(N%%, M%%) + ChlorineVel!(N%%, M%%)
  233.                 SodiumVel!(N%%, M%%) = SodiumVel!(N%%, M%%) + SodiumAcc!(N%%, M%%)
  234.                 IF ABS(SodiumVel!(N%%, M%%)) > Kelvin! THEN SodiumVel!(N%%, M%%) = Kelvin! * (ABS(SodiumVel!(N%%, M%%)) / SodiumVel!(N%%, M%%))
  235.                 ChlorineVel!(N%%, M%%) = ChlorineVel!(N%%, M%%) + ChlorineAcc!(N%%, M%%)
  236.                 IF ABS(ChlorineVel!(N%%, M%%)) > Kelvin! THEN ChlorineVel!(N%%, M%%) = Kelvin! * (ABS(ChlorineVel!(N%%, M%%)) / ChlorineVel!(N%%, M%%))
  237.             NEXT M%%
  238.         END IF
  239.     NEXT N%%
  240.     'Pause/Adjust for orthogonal forces
  241.     IF NOT Paused` THEN
  242.         _PUTIMAGE (ScreenX% - 100, 20), Pause&
  243.         FOR N%% = 0 TO NoBalls%% - 1
  244.             FOR M%% = 0 TO 5 'the six orthogonal positions from each sodium atom
  245.                 CALL Orthogonal(N%%, M%%) 'Move chlorine atom
  246.             NEXT M%%
  247.         NEXT N%%
  248.         ViewAngle! = ViewAngle! + 0.008
  249.         IF ViewAngle! > _PI THEN ViewAngle! = ViewAngle! - 2 * _PI
  250.         IF NoBalls%% < TotBalls%% THEN Count% = Count% + 1
  251.         IF NoBalls%% = NoSeed%% THEN
  252.             IF Count% >= 2000 AND ((ViewAngle! > -0.05 AND ViewAngle! < 0.05) OR (ViewAngle! > -_PI - 0.05 AND ViewAngle! < 0.05 - _PI)) THEN
  253.                 NoBalls%% = NoBalls%% + 2
  254.                 Count% = 0
  255.             END IF
  256.             'might try the angle of the next ball, not just viewing angle - future version
  257.         ELSEIF Count% >= 100 AND NoBalls%% < TotBalls% AND ((ViewAngle! > -0.05 AND ViewAngle! < 0.05) OR (ViewAngle! > -_PI - 0.05 AND ViewAngle! < 0.05 - _PI)) THEN
  258.             NoBalls%% = NoBalls%% + 2
  259.             Count% = 0
  260.         END IF
  261.     ELSE
  262.         _PUTIMAGE (ScreenX% - 100, 20), Continue&
  263.     END IF
  264.     'Draw Bonds
  265.     IF NOT DrawBonds` THEN
  266.         _PUTIMAGE (ScreenX% - 200, 20), Bonds&
  267.     ELSE
  268.         _PUTIMAGE (ScreenX% - 200, 20), NoBonds&
  269.     END IF
  270.     _PUTIMAGE (ScreenX% - 100, ScreenY% - 120), Quit&
  271.     LOCATE 1, 1: PRINT NoBalls%%;
  272.     _DISPLAY
  273.     IF INKEY$ <> "" THEN ASaltyDog` = False
  274.  
  275.  
  276. FUNCTION Attraction! (Dist!)
  277.     Attraction! = A0! * (1 / (Dist! / A2!) ^ A1!)
  278.  
  279. FUNCTION Repulsion! (Dist!)
  280.     Repulsion! = -R0! * (1 / (Dist! / R2!) ^ R1!)
  281.  
  282. FUNCTION XDash! (X!, Z!)
  283.     XDash! = X! * COS(ViewAngle!) + Z! * SIN(ViewAngle!)
  284.  
  285. FUNCTION ZDash! (X!, Z!)
  286.     ZDash! = -X! * SIN(ViewAngle!) + Z! * COS(ViewAngle!)
  287.  
  288. SUB Orthogonal (P%%, Q%%)
  289.     OnlyOneChlorine%% = True
  290.     NoChlorines%% = 0
  291.     R%% = 0
  292.     WHILE R%% <= NoBalls%% - 1 AND OnlyOneChlorine%%
  293.         IF R%% <> P%% THEN
  294.             Sepn! = SQR((SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)) * (SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)) + (SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)) * (SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)) + (SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)) * (SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)))
  295.             IF Sepn! < Atom! THEN
  296.                 X! = SodiumPos!(R%%, 0) - SodiumPos!(P%%, 0)
  297.                 Y! = SodiumPos!(R%%, 1) - SodiumPos!(P%%, 1)
  298.                 Z! = SodiumPos!(R%%, 2) - SodiumPos!(P%%, 2)
  299.                 SELECT CASE Q%%
  300.                     CASE 0
  301.                         S1! = SQR(Y! * Y! + Z! * Z!)
  302.                         Theta! = _ATAN2(S1!, X!)
  303.                         IF X! > 0 AND X! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  304.                     CASE 1
  305.                         S1! = SQR(X! * X! + Z! * Z!)
  306.                         Theta! = _ATAN2(S1!, Y!)
  307.                         IF Y! > 0 AND Y! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  308.                     CASE 2
  309.                         S1! = SQR(Y! * Y! + X! * X!)
  310.                         Theta! = _ATAN2(S1!, Z!)
  311.                         IF Z! > 0 AND Z! < Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  312.                     CASE 3
  313.                         S1! = SQR(Y! * Y! + Z! * Z!)
  314.                         Theta! = _ATAN2(S1!, -X!)
  315.                         IF X! < 0 AND X! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  316.                     CASE 4
  317.                         S1! = SQR(X! * X! + Z! * Z!)
  318.                         Theta! = _ATAN2(S1!, -Y!)
  319.                         IF Y! < 0 AND Y! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  320.                     CASE ELSE '5
  321.                         S1! = SQR(Y! * Y! + X! * X!)
  322.                         Theta! = _ATAN2(S1!, -Z!)
  323.                         IF Z! < 0 AND Z! > -Atom! AND ABS(Theta!) < ThetaMax! THEN OnlyOneChlorine%% = False
  324.                 END SELECT
  325.             END IF
  326.         END IF
  327.         IF OnlyOneChlorine%% THEN
  328.             Sepn! = SQR((ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)) * (ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)) + (ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)) * (ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)) + (ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)) * (ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)))
  329.             IF Sepn! < Atom! THEN
  330.                 X! = ChlorinePos!(R%%, 0) - SodiumPos!(P%%, 0)
  331.                 Y! = ChlorinePos!(R%%, 1) - SodiumPos!(P%%, 1)
  332.                 Z! = ChlorinePos!(R%%, 2) - SodiumPos!(P%%, 2)
  333.                 SELECT CASE Q%%
  334.                     CASE 0
  335.                         S1! = SQR(Y! * Y! + Z! * Z!)
  336.                         Theta! = _ATAN2(S1!, X!)
  337.                         IF X! > 0 AND X! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  338.                             NoChlorines%% = NoChlorines%% + 1
  339.                             ROne%% = R%%
  340.                         END IF
  341.                     CASE 1
  342.                         S1! = SQR(X! * X! + Z! * Z!)
  343.                         Theta! = _ATAN2(S1!, Y!)
  344.                         IF Y! > 0 AND Y! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  345.                             NoChlorines%% = NoChlorines%% + 1
  346.                             ROne%% = R%%
  347.                         END IF
  348.                     CASE 2
  349.                         S1! = SQR(Y! * Y! + X! * X!)
  350.                         Theta! = _ATAN2(S1!, Z!)
  351.                         IF Z! > 0 AND Z! < Atom! AND ABS(Theta!) < ThetaMax! THEN
  352.                             NoChlorines%% = NoChlorines%% + 1
  353.                             ROne%% = R%%
  354.                         END IF
  355.                     CASE 3
  356.                         S1! = SQR(Y! * Y! + Z! * Z!)
  357.                         Theta! = _ATAN2(S1!, -X!)
  358.                         IF X! < 0 AND X! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  359.                             NoChlorines%% = NoChlorines%% + 1
  360.                             ROne%% = R%%
  361.                         END IF
  362.                     CASE 4
  363.                         S1! = SQR(X! * X! + Z! * Z!)
  364.                         Theta! = _ATAN2(S1!, -Y!)
  365.                         IF Y! < 0 AND Y! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  366.                             NoChlorines%% = NoChlorines%% + 1
  367.                             ROne%% = R%%
  368.                         END IF
  369.                     CASE ELSE '5
  370.                         S1! = SQR(Y! * Y! + X! * X!)
  371.                         Theta! = _ATAN2(S1!, -Z!)
  372.                         IF Z! < 0 AND Z! > -Atom! AND ABS(Theta!) < ThetaMax! THEN
  373.                             NoChlorines%% = NoChlorines%% + 1
  374.                             ROne%% = R%%
  375.                         END IF
  376.                 END SELECT
  377.                 IF NoChlorines%% > 1 THEN OnlyOneChlorine%% = False
  378.             END IF
  379.         END IF
  380.         R%% = R%% + 1
  381.     WEND
  382.     IF NoChlorines%% = 0 THEN OnlyOneChlorine%% = False
  383.     IF OnlyOneChlorine%% THEN
  384.         'Move Chlorine Atom
  385.         X! = ChlorinePos!(ROne%%, 0) - SodiumPos!(P%%, 0)
  386.         Y! = ChlorinePos!(ROne%%, 1) - SodiumPos!(P%%, 1)
  387.         Z! = ChlorinePos!(ROne%%, 2) - SodiumPos!(P%%, 2)
  388.         SELECT CASE Q%%
  389.             CASE 0, 3
  390.                 ChlorinePos!(ROne%%, 1) = ChlorinePos!(ROne%%, 1) - Y! * (1 - Xstal!)
  391.                 ChlorinePos!(ROne%%, 2) = ChlorinePos!(ROne%%, 2) - Z! * (1 - Xstal!)
  392.             CASE 1, 4
  393.                 ChlorinePos!(ROne%%, 0) = ChlorinePos!(ROne%%, 0) - X! * (1 - Xstal!)
  394.                 ChlorinePos!(ROne%%, 2) = ChlorinePos!(ROne%%, 2) - Z! * (1 - Xstal!)
  395.             CASE 2, 5
  396.                 ChlorinePos!(ROne%%, 0) = ChlorinePos!(ROne%%, 0) - X! * (1 - Xstal!)
  397.                 ChlorinePos!(ROne%%, 1) = ChlorinePos!(ROne%%, 1) - Y! * (1 - Xstal!)
  398.         END SELECT
  399.     END IF
  400.  
  401. SUB CentreOfMass 'centre on original seed atoms
  402.     TotMass! = 0
  403.     MRx! = 0: MRy! = 0: MRz! = 0
  404.     Px! = 0: Py! = 0: Pz! = 0
  405.     FOR N% = 0 TO NoSeed%% - 1
  406.         TotMass! = TotMass! + 1
  407.         MRx! = MRx! + SodiumPos!(N%, 0)
  408.         MRy! = MRy! + SodiumPos!(N%, 1)
  409.         MRz! = MRz! + SodiumPos!(N%, 2)
  410.         Px! = SodiumVel!(N%, 0) + Px!
  411.         Py! = SodiumVel!(N%, 1) + Py!
  412.         Pz! = SodiumVel!(N%, 2) + Pz!
  413.         TotMass! = TotMass! + 1
  414.         MRx! = MRx! + ChlorinePos!(N%, 0)
  415.         MRy! = MRy! + ChlorinePos!(N%, 1)
  416.         MRz! = MRz! + ChlorinePos!(N%, 2)
  417.         Px! = ChlorineVel!(N%, 0) + Px!
  418.         Py! = ChlorineVel!(N%, 1) + Py!
  419.         Pz! = ChlorineVel!(N%, 2) + Pz!
  420.     NEXT N%
  421.     FOR N% = 0 TO NoSeed%% - 1
  422.         SodiumPos!(N%, 0) = SodiumPos!(N%, 0) - (MRx! / TotMass!)
  423.         SodiumPos!(N%, 1) = SodiumPos!(N%, 1) - (MRy! / TotMass!)
  424.         SodiumPos!(N%, 2) = SodiumPos!(N%, 2) - (MRz! / TotMass!)
  425.         SodiumVel!(N%, 0) = SodiumVel!(N%, 0) - (Px! / TotMass!)
  426.         SodiumVel!(N%, 1) = SodiumVel!(N%, 1) - (Py! / TotMass!)
  427.         SodiumVel!(N%, 2) = SodiumVel!(N%, 2) - (Pz! / TotMass!)
  428.         ChlorinePos!(N%, 0) = ChlorinePos!(N%, 0) - (MRx! / TotMass!)
  429.         ChlorinePos!(N%, 1) = ChlorinePos!(N%, 1) - (MRy! / TotMass!)
  430.         ChlorinePos!(N%, 2) = ChlorinePos!(N%, 2) - (MRz! / TotMass!)
  431.         ChlorineVel!(N%, 0) = ChlorineVel!(N%, 0) - (Px! / TotMass!)
  432.         ChlorineVel!(N%, 1) = ChlorineVel!(N%, 1) - (Py! / TotMass!)
  433.         ChlorineVel!(N%, 2) = ChlorineVel!(N%, 2) - (Pz! / TotMass!)
  434.     NEXT N%
  435.