summaryrefslogtreecommitdiff
path: root/new/self-langevin-motion.f90
diff options
context:
space:
mode:
authorConnor Moore <connor@hhmoore.ca>2026-02-25 12:30:49 -0500
committerConnor Moore <connor@hhmoore.ca>2026-02-25 12:30:49 -0500
commit571d4584514bf61412bc3613c7d285cb040bf93d (patch)
tree1956d41c4b2fb352f7c1f8d285f3777f36a21f94 /new/self-langevin-motion.f90
parent03cd33443240ae62be82fb8f98cf52df1a441182 (diff)
Added new version of code supporting vectorization
Diffstat (limited to 'new/self-langevin-motion.f90')
-rw-r--r--new/self-langevin-motion.f90177
1 files changed, 177 insertions, 0 deletions
diff --git a/new/self-langevin-motion.f90 b/new/self-langevin-motion.f90
new file mode 100644
index 0000000..167da70
--- /dev/null
+++ b/new/self-langevin-motion.f90
@@ -0,0 +1,177 @@
+program langevin_motion
+
+ use, intrinsic :: iso_fortran_env
+ use :: omp_lib
+
+ implicit none
+
+ !> Define some basic parameters
+ integer(int64), parameter :: n = 1000
+ real(real64), parameter :: pi = 2.0*asin(1.0)
+ real(real64), parameter :: L = 1.0
+
+ !> Numerical constants and such
+ real(real64), parameter :: dt = 0.005
+ real(real64), parameter :: t_max = 10.0
+ real(real64), parameter :: kT = 10.0
+ real(real64), parameter :: g = 1.0
+ real(real64), parameter :: m = 1.0
+ real(real64), parameter :: eps = 1.0
+ real(real64), parameter :: sigma = 1E-03
+ real(real64), parameter :: rc = sigma*2**(1.0/6.0)
+ real(real64), parameter :: pref1 = g, pref2 = sqrt(24.0*kT*g/dt)
+
+ !> And non-constants
+ real(real64) :: t
+ real(real64), dimension(n) :: dx, dy, dn
+ real(real64), dimension(n) :: F
+ real(real64) :: ran1, ran2
+ integer(int64) :: i
+
+ !> Vectors for positon, velocity, acceleration, and tracking
+ real(real64), dimension(n) :: px, py, vx, vy, ax, ay, vhx, vhy
+ logical, dimension(n) :: is_tracked = .TRUE., are_interacting
+
+ !> Start by initializing the particles with a random pos. and vel.
+ call initialize_particles(px, py, vx, vy, ax, ay, kT, L, pi)
+
+ !> Now simulate!
+ do while (t .lt. t_max)
+
+ !> Update half-step velocities
+ vhx = vx + 0.5*ax*dt
+ vhy = vy + 0.5*ay*dt
+
+ !> Update the positions
+ px = px + vhx*dt
+ py = py + vhy*dt
+
+ !> Impose the boundary conditions
+ call impose_BC(px, py, vhx, vhy, is_tracked, L)
+
+ !> Find the new acceleration
+ ax = 0.0
+ ay = 0.0
+
+ call random_number(ran1)
+ ran1 = ran1 - 0.5
+ call random_number(ran2)
+ ran2 = ran2 - 0.5
+
+ !> Random force
+ ax = ax - pref1*vhx + ran1
+ ay = ay - pref1*vhy + ran2
+
+ !> Particle-particle interaction force
+ interactions: do i = 1,n
+
+ !> Calculate the distance between the particles:
+ dx = px - px(i)
+ dy = py - py(i)
+ dn = sqrt(dx**2 + dy**2)
+
+ !> Check which particles are interacting
+ are_interacting = (dn .gt. 0.0) .and. (dn .lt. rc) .and. is_tracked
+
+ !> Start with no forces
+ F = 0.0
+
+ where (are_interacting)
+
+ !> Lennardn-Jones force
+ F = 4.0*eps*(-12.0*sigma**12/dn**13 + 6.0*sigma**6/dn**7)
+
+ end where
+
+ !> Update the accelerations with the new force when a force was calculated
+ ax(i) = ax(i) + sum(F*dx / (dn*m), mask=are_interacting)
+ ay(i) = ay(i) + sum(F*dy / (dn*m), mask=are_interacting)
+
+ end do interactions
+
+ !> Update full velocities
+ vx = vhx + 0.5*ax*dt
+ vy = vhy + 0.5*ay*dt
+
+ !> Update timestep
+ t = t + dt
+
+ !> Print posiitons to stdout
+ print '(e24.12,e24.12)', (px(i), py(i), i=1,n)
+
+ !> This splits timesteps into data blocks for Gnuplot
+ print *
+ print *
+
+ end do
+
+contains
+
+ impure elemental subroutine initialize_particles(px, py, vx, vy, ax, ay, kT, L, pi)
+ real(real64), intent(in out) :: px, py, vx, vy, ax, ay
+ real(real64), intent(in) :: kT, L, pi
+ real(real64) :: ran1, ran2
+
+ !> Random number seed
+ call random_seed()
+
+ !> And 2 random numbers
+ call random_number(ran1)
+ call random_number(ran2)
+
+ !> Initial position
+ px = L*(ran1-0.5)
+ py = L*(ran2-0.5)
+
+ !> Initial acceleration is zero
+ ax = 0.0
+ ay = 0.0
+
+ !> New random numbers
+ call random_number(ran1)
+ call random_number(ran2)
+
+ !> Initial velocity using Box-Muller transform
+ vx = sqrt(kT/m)*sqrt(-2.0*log(ran1))*cos(2*pi*ran2)
+ vy = sqrt(kT/m)*sqrt(-2.0*log(ran1))*sin(2*pi*ran2)
+
+ end subroutine initialize_particles
+
+ pure elemental subroutine impose_BC(px, py, vhx, vhy, is_tracked, L)
+ real(real64), intent(in out) :: px, py, vhx, vhy
+ real(real64), intent(in) :: L
+ logical, intent(in out) :: is_tracked
+
+ if (is_tracked) then
+ !> Top boundary
+ if (py.gt.L/2) then
+ py = L - py
+ vhy = -vhy
+ end if
+
+ !> Bottom boundary
+ if (py.lt.-L/2) then
+ py = -L - py
+ vhy = -vhy
+ end if
+
+ !> Left boundary
+ if (px.gt.L/2) then
+ px = L - px
+ vhx = -vhx
+ end if
+
+ !> Right boundary
+ if (px.lt.-L/2) then
+ px = -L - px
+ vhx = -vhx
+ end if
+
+ !> If the particle is still outside, it goes into the garbage
+ if (abs(px).gt.L/2 .or. abs(py) .gt. L/2) is_tracked = .false.
+
+ end if
+
+ end subroutine impose_BC
+
+end program langevin_motion