McGill University
School of Computer Science

Computer Science COMP 199 (Winter term)
Excursions in Computing Science

%MATLABpak09cII:
%
%	2D kinetic gas simulator and support programs in order of appearance
%	(Anything ending Sim.m is a modification of collSim.m: compare!)
%
%	molCollWallCountBot.m			moleculeCollide.m
%	molCollWallWhen.m			
%
%	condif.m				implies.m
%	nonnegrows.m				minrows.m
%
%	moleculeCollWhen.m			moleculeInit.m
%
%	genDirection.m				genNormal.m
%
%	collSim.m
%
%	molDatHisto.m				statSim.m
%
%	momenCumHisto.m				molDataDistr.m
%
%	cumuSim.m
%
%	FTfluct.m				FTfluctAgg.m
%	momAvgHisto.m				FTfluctVar.m
%
%	manyInits.m
%
%	energyHisDis.m				entrSim.m
%
%	molCollWallWhen.m (reprise)		molCollWallCountBot.m (reprise)
%
%	tmptureSim.m
%
%	smooth2enerIgn.m
%
%	presSim.m				press2Sim.m
%
%	chmpotSim.m
%

% function p = molCollWallCountBot(pb,1,1,abcd,r,c,0)		THM	101025
% given vectors momentum pb, box boundaries abcd, position c; scalar radius r
% find new momentum p
function p = molCollWallCountBot(pb,tmult,bmult,abcd,r,c,cntB)
% tmult = 1; bmult = 1; cntB = 0;		% for future refinement
abr = abcd - [-r,r,-r,r];	% extend wall to _centre_ of molecule
p = pb;				% initialize: momentum out = momentum in
if c(1) < abr(1) | c(1) > abr(2) | c(2) < abr(3) | c(2) > abr(4)
  display(['molCollWallCountBot: ' num2str(c') ' out of box ' num2str(abr)])
elseif (c(1)==abr(1) | c(1)==abr(2)) & (c(2)==abr(3) | c(2)==abr(4)), p = -pb;
					% 4 corners: reverse momentum
elseif c(1)==abr(1) | c(1)==abr(2), p(1) = -pb(1);%side wall: reverse x-momentum
elseif c(2) == abr(4), p(2) = -pb(2);	%top: reverse y-momentum
elseif c(2) == abr(3), p(2) = -pb(2);	%bot: reverse y-momentum
else display('molCollWallCountBot: no wall collision')
end %if

% function [p1,p2] = moleculeCollide(m1,m2,p1b,p2b,0,C12)  THM		101025
% input masses (units don't matter: only ratios used)
%	initial momenta (typically opposite signs): column vectors
%	C12 is column vector connecting centres at collision time = c2 - c1
% output momentum column vectors
function [p1,p2] = moleculeCollide(m1,m2,p1b,p2b,mhf,C12)
mhf = 0;		% for future refinement
pc = p1b + p2b;		% momentum of CoM
a = m1/(m1+m2);		% dimensionless ratio for conversion to CoM
p1bc = p1b - a*pc;	% CoM momentum of first molecule
p2bc = p2b - (1-a)*pc;	% CoM momentum of second molecule	% p2bc = - p1bc
c12 = C12/sqrt(C12'*C12);	% normalize centre-to-centre vector
dim=size(c12);
reflect = 2*c12*c12' - eye(dim(1));	% reflection matrix: Week 7c Note 8
p1c = -reflect*p1bc;	% CoM momentum after collision
p2c = -p1c;		% CoM momentum after collision
p1 = p1c + a*pc;	% convert back from CoM coordinates
p2 = p2c + (1-a)*pc;	% ditto

% function [t,c] = molCollWallWhen(cb,p,M,r,abcd)	THM		101025
% find
%   time of collision, t
%   centre after collision:
%     [a-r;y] for right, [r-a;y] for left, [x;b-r] for top, [x,r-b] for bottom
%     - could use sum of appropriate for corner, but let's default to wall
%       if a tie, then schedule an immediate hit on top or bottom
% given
%   centre of molecule at time 0, column vector cb
%   momentum, column vector p
%   mass (amu), M
%   vector abcd describing box (abcd(1),abcd(2))*(abcd(3),abcd(4))
% uses	v = condif(cond,then,els);
%	z = implies(x,y);
%	found = nonnegrows(matrix);
%	found = minrows(matrix);
function [t,c] = molCollWallWhen(cb,p,M,r,abcd)
 m = M*10.36;		% convert from amu to milli-eV (ps/nm)^2
 v = p/m;		% velocity
% distances from location  cb  to wall or middle horizontal diaphragm
 dap = abcd(2) - r - cb(1);	% positive distance to vertical wall
 dav = abcd(1) + r - cb(1);	% negative distance to vertical wall
 dbp = abcd(4) - r - cb(2);	% positive distance to horizontal wall
 dbv = abcd(3) + r - cb(2);	% negative distance to horizontal wall
% if distance==0 then depend on sign of  v ; time is dist/v; new molecule pos, c
 record(1,:) = condif(implies(dap==0,v(1)>0),[dap/v(1),abcd(2)-r,cb(2)+v(2)*dap/v(1)],[inf,0,0]);
 record(2,:) = condif(implies(dav==0,v(1)<0),[dav/v(1),abcd(1)+r,cb(2)+v(2)*dav/v(1)],[inf,0,0]);
 record(3,:) = condif(implies(dbp==0,v(2)>0),[dbp/v(2),cb(1)+v(1)*dbp/v(2),abcd(4)-r],[inf,0,0]);
 record(4,:) = condif(implies(dbv==0,v(2)<0),[dbv/v(2),cb(1)+v(1)*dbv/v(2),abcd(3)+r],[inf,0,0]);
 next = minrows(nonnegrows(record));	% 2 identical if corner, else 1
 sizeNext = size(next);			% display test only
 t = next(1,1);			% time is smallest of the 5 times
 c = [next(1,2);next(1,3)];	% new position of molecule 4 corresponding event

% function v = condif(cond,then,els)			THM		101025
% conditional expression: getting around a MATLAB omission
function v = condif(cond,then,els)
if cond, v = then; else v = els; end % if

% function z = implies(x,y)				THM		101025
% the Boolean expression x => y ("if x then y") is formally equivalent to
%			~x|y, which is the same as y|~x ("y or not x")
function z = implies(x,y)
z = ~x | y;

% function found = nonnegrows(matrix)			THM		101025
% find rows of matrix whose first element is nonnegative
function found = nonnegrows(matrix)
sizeMatrix = size(matrix);
found = [];
for j = 1:sizeMatrix(1)
  if matrix(j,1)>=0, found = [found; matrix(j,:)]; end % if
end % for j

% function found = minrows(matrix)			THM		101025
% return all rows of a rectangular matrix with smallest first element
function found = minrows(matrix)
sizeMatrix = size(matrix);
found = matrix(1,:);
for j = 2:sizeMatrix(1)
  if matrix(j,1) < found(1,1)
    found = matrix(j,:);
  elseif matrix(j,1) == found(1,1)
    found = [found; matrix(j,:)];
  end % if compare
end % for j

% function [t,c1,c2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2) THM 101025
% find
%   time of collision, t (if imag(t)~=0 then no collision)
%   centres of each molecule at collision, column vectors c1, c2
% given
%   centres of each molecule at time 0, column vectors c1b, c2b
%   masses and momenta of each molecule, M1, M2, column vectors p1b, p2b
%   radii of each molecule, r1, r2
% uses x = quadratic(a,b,c)
function [t,c1,c2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2)
 m1 = M1*10.36;	% convert from amu to merts (meV(ps/nm)^2)
 m2 = M2*10.36;	% convert from amu to merts (meV(ps/nm)^2)
v1b = p1b/m1;		% find velocity of first molecule (nm/ps)
v2b = p2b/m2;		% find velocity of second molecule (nm/ps)
v = v1b - v2b;		% make second molecule stationary
c = c1b - c2b;		% centre second molecule at origin
r = r1 + r2;		% expand 2nd molecule to radius r, shrink 1st to point
if v'*v==0, t = inf; c1 = c1b; c2 = c2b; return, end % if	% parallel vels
t = min(quadratic(v'*v,2*c'*v,c'*c - r^2));		% display test only
c1 = c + v1b*t + c2b;	% move 1st molecule, then transform 2nd away from origin
c2 = v2b*t + c2b;	% transform 2nd away from origin
if t<-eps*10^3 | abs(imag(t))>eps	% flag coincident or no collision
  t = inf;
end % if t<0 |

% function molData = moleculeInit(N,T,startRange,r,M)		THM	101026
% given number of molecules N, temperature T, molecular radius r (nm) and
%  mass M (AMU);
%     NB 40 degC == 313.15 degK == 27 meV (26.9935 using k = .0862)
%  startRange is array (posLo, posHi, stdev, momLo, momHi) for the
%  initial positions of the molecules (angles in degrees, stdev in nm)
% find N*7 array molData, columns cx,cy,px,py,r,M,E
% uses genDirection(range)	(uniformly distributed angular direction)
%      genNormal(stdev)	(Normally distributed position on line, given stdev)
function molData = moleculeInit(N,T,startRange,r,M)
startDirRange = [startRange(1),startRange(2)]*pi/180;
stdev = startRange(3);
startLoc = [startRange(4),startRange(5)];
momDirRange = [startRange(6),startRange(7)]*pi/180;
%for k = 1:N
k = 1;
% duplicates = [];			% track duplicates: test only
while true		% loop over N molecules, but pass over any duplicates
  dirStart = genDirection(startDirRange);
  c = genNormal(stdev)*[cos(dirStart),sin(dirStart)] + startLoc;
  dirMom = genDirection(momDirRange);		     % changed 100317
  % uniform momenta (changed 100602,100606):
  E = (1 + (2*rand(1)-1)*sqrt(2)/10)*0.0862*T;	% avg +/- (-1 -- 1)rt2/10
  p = sqrt(2*10.36*M*E)*[cos(dirMom),sin(dirMom)];
  moldata = [c(1),c(2),p(1),p(2),r,M,E];
  duplicate = false;
  for j = 1:k-1			% a very slow way of checking for duplicates
    if min(moldata==molData(j,:))		% min = and for boolean array
%      duplicates = [duplicates;[k,j,moldata]];% track duplicates: test only
      duplicate = true;
      break					% full duplicate found
	% NB it doesn't matter if partial duplicate, e.g., positions coincide
    end % if min()
  end % for j
  if ~duplicate | k==1
      molData(k,:) = moldata;			% record unique initial molecule
      k = k + 1;
  end % if ~duplicate
  if k>N, break, end %if
end % while true (aka  for k)

% function a = genDirection(range)		THM			100301
% generate random direction in range(1)--range(2)
function a = genDirection(range)
lowangle = range(1);
anglerange = range(2) - lowangle;
a = lowangle + anglerange*rand(1);

% function d = genNormal(stdev)			THM			100301
% given standerd deviation stdev
% find a distance d from centre
% uses erfNormal(stdev,decpl)  to give cumulative sum of Normal
function d = genNormal(stdev)
% Following \cite[p.263]{Ross:prob} to generate random variable X from uniform u:
%       generate uniform random u on [0,1];
%	p = erfNormal^{-1}(u)
if stdev == 0, d = 0; else
  u = rand(1);			% uniform random
  for d = 0:0.03*stdev:3*stdev
    if erfNormal(d,2) > u, break, end %if
  end % for d
  s = rand(1);
  if s<=0.5, signd = -1; else signd = 1; end
  d = signd*d;
end % if stdev

% function molData = collSim(N,T,r,M,ab)	THM			101026
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return nothing (collision simulation only, no stats); molData is sop;see below
% uses	molData = moleculeInit(N,T,startRange,r,M)
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
function molData = collSim(N,T,r,M,ab)
tic					% elapsed time

% initialize
startRange = [0,0,5,0,0,40,50];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
molData = moleculeInit(N,T,startRange,r,M)	% display test only
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,stepChunk)==0
      elapsed = toc;				% elapsed time
      chunkNo = chunkNo + 1;
      if firstChunk
	firstChunk = false;
      end % if firstChunk
      beep
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/n '],'s');
      if isempty(reply)
          reply = 'y';
      end
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
      end % if reply
    end % if mod()
  end % if collision
end % while(true)

% function molDatAverage = molDataHisto(molData,molDatAverage) THM 101028
% plot histogram of statistics from statSim()
% given
%	molData, N*7 array of [cx,cy,px,py,4,M,E] to which we'll add p
%	molDatAverage, initially [], average of all these
% find
%	molDatAverage = [molDatAverage;molDatAvg]
function molDatAverage = molDataHisto(molData,molDatAverage)
molData(:,8) = sqrt(molData(:,3).^2 + molData(:,4).^2);	% momentum magnitude
sizeMolData = size(molData);
% firstInvocation = size(molDatAverage)==[0,0];% initially [0,0] (or invokNo==1)
sizeMolDataAvg = size(molDatAverage);
invokNo = sizeMolDataAvg(1) + 1;
firstInvocation = invokNo==1;			% initially
molDatAvg = sum(molData)/sizeMolData(1)
molDatAverage = [molDatAverage;molDatAvg];
%molDataStdev = sqrt(sum(molData.^2-molDatAverage.^2)/sizeMolData(1))
molDatBucket = zeros(10,5);
bw = 10;		% bucket width
for k = 1:4				% momentum (1,2), energy (3), |p| (4)
  k1 = condif(k<3,k+2,k+4);		% 1->3 (px), 2->4 (py), 3->7 (E), 4->8
  bs = condif(k<3,-5*bw,0);		% bucket start
  for j = 1: sizeMolData(1)
    if molData(j,k1) < bs + bw, molDatBucket(1,k) = molDatBucket(1,k) + 1;
    elseif molData(j,k1) < bs + 2*bw, molDatBucket(2,k) = molDatBucket(2,k) + 1;
    elseif molData(j,k1) < bs + 3*bw, molDatBucket(3,k) = molDatBucket(3,k) + 1;
    elseif molData(j,k1) < bs + 4*bw, molDatBucket(4,k) = molDatBucket(4,k) + 1;
    elseif molData(j,k1) < bs + 5*bw, molDatBucket(5,k) = molDatBucket(5,k) + 1;
    elseif molData(j,k1) < bs + 6*bw, molDatBucket(6,k) = molDatBucket(6,k) + 1;
    elseif molData(j,k1) < bs + 7*bw, molDatBucket(7,k) = molDatBucket(7,k) + 1;
    elseif molData(j,k1) < bs + 8*bw, molDatBucket(8,k) = molDatBucket(8,k) + 1;
    elseif molData(j,k1) < bs + 9*bw, molDatBucket(9,k) = molDatBucket(9,k) + 1;
    elseif molData(j,k1) < bs + 10*bw, molDatBucket(10,k) = molDatBucket(10,k) + 1;
    else % ignore energentum over 100
    end % if molData
  end % for j
end % for k
colour = 'rbgkm';
invokNo,clr = colour(mod(invokNo-1,5)+1)	% display test only
j=1:10;
subplot(3,2,1)
if firstInvocation, hold off, end
plot(bw*(j-5),molDatBucket(:,1),clr)
title('momentum x')
hold on
subplot(3,2,2)
if firstInvocation, hold off, end
plot(bw*(j-5),molDatBucket(:,2),clr)
title('momentum y')
hold on
subplot(3,2,3)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,4),clr)
title('momentum magn.')
hold on
subplot(3,2,4)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,3),clr)
title('energy')
hold on
subplot(3,2,5)
if firstInvocation, hold off, end
scatter(molDatAvg(3),molDatAvg(4),clr)
xlabel('p_x')
ylabel('p_y')
title('average momentum')
hold on
subplot(3,2,6)
if firstInvocation, hold off, end
scatter(molDatAvg(1),molDatAvg(2),clr)
xlabel('c_x')
ylabel('c_y')
title('average position')
hold on

% function molDatAverage = molDataHisto(molData,molDatAverage) THM 101028
% plot histogram of statistics from statSim()
% given
%	molData, N*7 array of [cx,cy,px,py,4,M,E] to which we'll add p
%	molDatAverage, initially [], average of all these
% find
%	molDatAverage = [molDatAverage;molDatAvg]
function molDatAverage = molDataHisto(molData,molDatAverage)
molData(:,8) = sqrt(molData(:,3).^2 + molData(:,4).^2);	% momentum magnitude
sizeMolData = size(molData);
% firstInvocation = size(molDatAverage)==[0,0];% initially [0,0] (or invokNo==1)
sizeMolDataAvg = size(molDatAverage);
invokNo = sizeMolDataAvg(1) + 1;
firstInvocation = invokNo==1;			% initially
molDatAvg = sum(molData)/sizeMolData(1)
molDatAverage = [molDatAverage;molDatAvg];
%molDataStdev = sqrt(sum(molData.^2-molDatAverage.^2)/sizeMolData(1))
molDatBucket = zeros(10,5);
bw = 10;		% bucket width
for k = 1:4				% momentum (1,2), energy (3), |p| (4)
  k1 = condif(k<3,k+2,k+4);		% 1->3 (px), 2->4 (py), 3->7 (E), 4->8
  bs = condif(k<3,-5*bw,0);		% bucket start
  for j = 1: sizeMolData(1)
    if molData(j,k1) < bs + bw, molDatBucket(1,k) = molDatBucket(1,k) + 1;
    elseif molData(j,k1) < bs + 2*bw, molDatBucket(2,k) = molDatBucket(2,k) + 1;
    elseif molData(j,k1) < bs + 3*bw, molDatBucket(3,k) = molDatBucket(3,k) + 1;
    elseif molData(j,k1) < bs + 4*bw, molDatBucket(4,k) = molDatBucket(4,k) + 1;
    elseif molData(j,k1) < bs + 5*bw, molDatBucket(5,k) = molDatBucket(5,k) + 1;
    elseif molData(j,k1) < bs + 6*bw, molDatBucket(6,k) = molDatBucket(6,k) + 1;
    elseif molData(j,k1) < bs + 7*bw, molDatBucket(7,k) = molDatBucket(7,k) + 1;
    elseif molData(j,k1) < bs + 8*bw, molDatBucket(8,k) = molDatBucket(8,k) + 1;
    elseif molData(j,k1) < bs + 9*bw, molDatBucket(9,k) = molDatBucket(9,k) + 1;
    elseif molData(j,k1) < bs + 10*bw, molDatBucket(10,k) = molDatBucket(10,k) + 1;
    else % ignore energentum over 100
    end % if molData
  end % for j
end % for k
colour = 'rbgkm';
invokNo,clr = colour(mod(invokNo-1,5)+1)	% display test only
j=1:10;
subplot(3,2,1)
if firstInvocation, hold off, end
plot(bw*(j-5),molDatBucket(:,1),clr)
title('momentum x')
hold on
subplot(3,2,2)
if firstInvocation, hold off, end
plot(bw*(j-5),molDatBucket(:,2),clr)
title('momentum y')
hold on
subplot(3,2,3)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,4),clr)
title('momentum magn.')
hold on
subplot(3,2,4)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,3),clr)
title('energy')
hold on
subplot(3,2,5)
if firstInvocation, hold off, end
scatter(molDatAvg(3),molDatAvg(4),clr)
xlabel('p_x')
ylabel('p_y')
title('average momentum')
hold on
subplot(3,2,6)
if firstInvocation, hold off, end
scatter(molDatAvg(1),molDatAvg(2),clr)
xlabel('c_x')
ylabel('c_y')
title('average position')
hold on

% function molData = statSim(N,T,r,M,ab)	THM			101026
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = moleculeInit(N,T,startRange,r,M)
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
%	molDatAverage = molDataHisto(molData,[]);
function molData = statSim(N,T,r,M,ab)

% initialize
startRange = [0,0,5,0,0,40,50];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
molData = moleculeInit(N,T,startRange,r,M)	% display test only
molDatAverage = molDataHisto(molData,[]);
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,stepChunk)==0
      elapsed = toc;				% elapsed time
      chunkNo = chunkNo + 1;
      if firstChunk
	firstChunk = false;
      end % if firstChunk
      molDatAverage = molDataHisto(molData,molDatAverage);
      beep
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/n '],'s');
      if isempty(reply)
          reply = 'y';
      end
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
      end % if reply
    end % if mod()
  end % if collision
end % while(true)

% function [momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg) THM 101103
% accumulated magnitude of momentum and energy from molData into momenCum
% given
%	molData, N*7 array of [cx,cy,px,py,r,M,E] to which we'll add p
%	momenCum, initially zeros(11,2): 10 positions each for p, E
%	momenAvg, initially []: accumulates average momentum magnitude, energy
% find
%	momenCum
%	momenAvg
function [momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg)
molData(:,8) = sqrt(molData(:,3).^2 + molData(:,4).^2); % momentum magnitude
sizeMolData = size(molData);
molDatBucket = zeros(10,5);
bs = 0;				% bucket start
bw = 10;			% bucket width
for k = 1:2			% momentum magnitude (1), energy (2)
  k1 = condif(k==1,8,7);	% molData(8) is p, (7) is E
  for j = 1: sizeMolData(1)
    if molData(j,k1) < bs + bw, momenCum(1,k) = momenCum(1,k) + 1;
    elseif molData(j,k1) < bs + 2*bw, momenCum(2,k) = momenCum(2,k) + 1;
    elseif molData(j,k1) < bs + 3*bw, momenCum(3,k) = momenCum(3,k) + 1;
    elseif molData(j,k1) < bs + 4*bw, momenCum(4,k) = momenCum(4,k) + 1;
    elseif molData(j,k1) < bs + 5*bw, momenCum(5,k) = momenCum(5,k) + 1;
    elseif molData(j,k1) < bs + 6*bw, momenCum(6,k) = momenCum(6,k) + 1;
    elseif molData(j,k1) < bs + 7*bw, momenCum(7,k) = momenCum(7,k) + 1;
    elseif molData(j,k1) < bs + 8*bw, momenCum(8,k) = momenCum(8,k) + 1;
    elseif molData(j,k1) < bs + 9*bw, momenCum(9,k) = momenCum(9,k) + 1;
    elseif molData(j,k1) < bs + 10*bw, momenCum(10,k) = momenCum(10,k) + 1;
    else % ignore energentum over 100
    end % if molData
  end % for j
end % for k
momenAverage(1) = sum(molData(:,8))/10;		% average momentum magnitude
momenAverage(2) = sum(molData(:,7))/10;		% average energy
momenAvg = [momenAvg;momenAverage];

% function molDatAverage =
%	 molDataDistr(molData,molDatAverage,momenCum,momenAvg)	THM	101028
% plot histogram of statistics from statSim()
% given
%	molData, N*7 array of [cx,cy,px,py,r,M,E] to which we'll add p
%	molDatAverage, initially [], average of all these
%	momenCum, array of 10 buckets for each of momentum magnitude, energy
%	momenAvg, array of variable rows holding average mom magn, energy
%		(both these last supplied by function momenCumHisto)
% find
%	molDatAverage = [molDatAverage;molDatAvg]
function molDatAverage = molDataDistr(molData,molDatAverage,momenCum,momenAvg)
molData(:,8) = sqrt(molData(:,3).^2 + molData(:,4).^2);	% momentum magnitude
sizeMolData = size(molData);
% firstInvocation = size(molDatAverage)==[0,0];% initially [0,0] (or invokNo==1)
sizeMolDataAvg = size(molDatAverage);
invokNo = sizeMolDataAvg(1) + 1;
firstInvocation = invokNo==1;			% initially
secndInvocation = invokNo==2;	% or size(momenAvg)==[0,0]
momenAvg			% display test only
molDatAvg = sum(molData)/sizeMolData(1)		% display test only
molDatAverage = [molDatAverage;molDatAvg];
%molDataStdev = sqrt(sum(molData.^2-molDatAverage.^2)/sizeMolData(1))
molDatBucket = zeros(10,5);
bw = 10;		% bucket width
for k = 1:4	% kept, tho need only 2	% momentum (1,2), energy (3), |p| (4)
  k1 = condif(k<3,k+2,k+4);		% 1->3 (px), 2->4 (py), 3->7 (E), 4->8
  bs = condif(k<3,-5*bw,0);		% bucket start
  for j = 1: sizeMolData(1)
    if molData(j,k1) < bs + bw, molDatBucket(1,k) = molDatBucket(1,k) + 1;
    elseif molData(j,k1) < bs + 2*bw, molDatBucket(2,k) = molDatBucket(2,k) + 1;
    elseif molData(j,k1) < bs + 3*bw, molDatBucket(3,k) = molDatBucket(3,k) + 1;
    elseif molData(j,k1) < bs + 4*bw, molDatBucket(4,k) = molDatBucket(4,k) + 1;
    elseif molData(j,k1) < bs + 5*bw, molDatBucket(5,k) = molDatBucket(5,k) + 1;
    elseif molData(j,k1) < bs + 6*bw, molDatBucket(6,k) = molDatBucket(6,k) + 1;
    elseif molData(j,k1) < bs + 7*bw, molDatBucket(7,k) = molDatBucket(7,k) + 1;
    elseif molData(j,k1) < bs + 8*bw, molDatBucket(8,k) = molDatBucket(8,k) + 1;
    elseif molData(j,k1) < bs + 9*bw, molDatBucket(9,k) = molDatBucket(9,k) + 1;
    elseif molData(j,k1) < bs + 10*bw, molDatBucket(10,k) = molDatBucket(10,k) + 1;
    else % ignore energentum over 100
    end % if molData
  end % for j
end % for k
for j = 1:2					% normalize histo to distr
  momenCumDistr(:,j) = momenCum(:,j)/sum(momenCum(:,j));
end % for j
colour = 'bgkm';
invokNo,clr = colour(mod(invokNo-1,4)+1)	% display test only
j=1:10;
subplot(3,2,1)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,4),clr)
title('momentum magn.')
hold on
subplot(3,2,2)
if firstInvocation, hold off, end
plot(bw*j,molDatBucket(:,3),clr)
title('energy')
hold on
subplot(3,2,3)
if firstInvocation, hold off, end
plot(bw*j,momenCumDistr(:,1),clr)
title('cumulative momentum magn.')
hold on
subplot(3,2,4)
if firstInvocation, hold off, end
plot(bw*j,momenCumDistr(:,2),clr)
title('cumulative energy')
hold on
subplot(3,2,5)
if firstInvocation, hold off, end
plot(momenAvg(:,1))
title('average momentum magn.')
xlabel('time (# collisions)')
ylabel('meV-ps/nm')
hold on
subplot(3,2,6)
if firstInvocation, hold off, end
plot(momenAvg(:,2))
title('average energy')
xlabel('time (# collisions)')
ylabel('meV')
hold on

% function molData = cumuSim(N,T,r,M,ab)	THM			101102
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = moleculeInit(N,T,startRange,r,M)
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
%	[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg)
%	molDatAverage = molDataDistr(molData,molDatAverage,momenCum,momenAvg);
% Differs from statSim by introducing cumulative momentum magnitude and energy;
%  modifies histogram building and plotting routine, replacing momx, momy by
%  these new distributions, and scatter plots of mom, pos by fluctuation plots
%  of average momentum magnitude and energy.
function molData = cumuSim(N,T,r,M,ab)

% initialize
startRange = [0,0,5,0,0,40,50];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
molData = moleculeInit(N,T,startRange,r,M)	% display test only
molDatAverage = [];	% initialize for molDataDistr: no longer display initial
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
momenCum = zeros(10,2);	% initialize parameters for momenCumHist
momenAvg = [];		%  ditto
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if ~firstChunk
    % start accumulating, skipping the distortion of the initial motions
      if mod(happIndx,N)==0		% accumulate for every N collisions
	[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg);
      end % if mod(happIndx,N)==0
    end % if ~firstChunk
    if mod(happIndx,stepChunk)==0
      elapsed = toc;				% elapsed time
      chunkNo = chunkNo + 1;
      if firstChunk
	firstChunk = false;
      else
	molDatAverage = molDataDistr(molData,molDatAverage,momenCum,momenAvg);
      end % if firstChunk
      beep
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/n '],'s');
      if isempty(reply)
          reply = 'y';
      end
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
      end % if reply
    end % if mod()
  end % if collision
end % while(true)

% function [momAvgFT,mAapprox] = FTfluct		THM		101109
% Find discrete Fourier transform of hardwu=ired sequence momAvg: momAvgFT
% Manually select strongest frequency components (7 with largest magnitudes)
% and DFT back to mAapprox
function [momAvgFT,mAapprox] = FTfluct
momAvg = [42.2964;41.1153;42.0875;41.5578;42.5435;41.9132;40.2426;42.4980;41.3177;42.8827;41.9394;40.3250;40.0651;37.5326;37.4996;39.1918;40.4985;40.1718;39.0108;39.7756;39.3788;37.1139;39.9479;40.1349;38.4678;36.7253;34.7730;40.8269;39.9655;39.5493;40.2808;39.6370;38.1273;41.9592;41.8759;44.2589;42.9165;43.0852;42.8527;42.0199];
F40 = makeDFT(40);
momAvgFT = F40*momAvg;
mAapproxFT = zeros(size(momAvgFT));
momAvgFT = [momAvgFT, abs(momAvgFT)];
mAapproxFT(1,1) = momAvgFT(1,1);
mAapproxFT(2,1) = momAvgFT(2,1);
mAapproxFT(7,1) = momAvgFT(7,1);
mAapproxFT(4,1) = momAvgFT(4,1);
mAapproxFT(8,1) = momAvgFT(8,1);
mAapproxFT(17,1) = momAvgFT(17,1);
mAapproxFT(5,1) = momAvgFT(5,1);
for j = 2:19	% put in symmetric components
  mAapproxFT(42-j,1) = momAvgFT(j,1);
end % for j

mAapprox = conj(F40')*mAapproxFT;
mAapprox = [mAapprox,abs(mAapprox)];
plot(1:40,momAvg,'r',1:40,mAapprox(:,2),'b',1:40,momAvgFT(1,1)/sqrt(40),'k')
title('Fourier analysis of average momentum magnitude')
xlabel('time (# collisions/10)')
ylabel('average momentum magnitude')
legend('avg mom','largest 7 freq.','time average','Location','North')

% function momAvgFT = FTfluctAgg(aggSize,clr)		THM	101111
% Group the 40 values hardwired in momAvg into 40/aggSize (must be integer)
% aggregate averages. So aggSize may be 1,2,4,5,8,10,20,40. Then, with these,
% Take Fourier transform to find the principal frequencies.
%	clr is the plot colour
function momAvgFT = FTfluctAgg(aggSize,clr)
momAvg = [42.2964;41.1153;42.0875;41.5578;42.5435;41.9132;40.2426;42.4980;41.3177;42.8827;41.9394;40.3250;40.0651;37.5326;37.4996;39.1918;40.4985;40.1718;39.0108;39.7756;39.3788;37.1139;39.9479;40.1349;38.4678;36.7253;34.7730;40.8269;39.9655;39.5493;40.2808;39.6370;38.1273;41.9592;41.8759;44.2589;42.9165;43.0852;42.8527;42.0199];
sizeMomAvg = size(momAvg);
k = 0;
for j = 1:sizeMomAvg
  if aggSize==1 | mod(j,aggSize)==1
    if k>0, cumMomAvg(k) = cumMomAvg(k)/aggSize; end
    k = k + 1;
    cumMomAvg(k) = 0;
  end % if mod
  cumMomAvg(k) = cumMomAvg(k) + momAvg(j);
end % for k
cumMomAvg(k) = cumMomAvg(k)/aggSize;	% last term
noTerms = sizeMomAvg/aggSize;		% must be integer
DFT = makeDFT(noTerms(1));
momAvgFT = DFT*cumMomAvg';
momAvgFT = [momAvgFT, abs(momAvgFT)];
figure(3)			% hardwired: will wipe previous figure 3
plot(aggSize:aggSize:40,cumMomAvg,clr)
hold on				% must hold off before first invocation
title('momentum magnitude averages fluctuate')
xlabel('time (# collisions/10)')
ylabel('average momentum magnitude')

% function mimStats = momAvgHisto(aggSize,clr)		THM		101111
% Find and plot 10-element histogram for hardwired momentum magnitude averages:
% group the 40 values hardwired in momAvg into 40/aggSize (must be integer)
% aggregate averages. So aggSize may be 1,2,4,5,8,10,20,40.
%	clr is colour of plot
function momStats = momAvgHisto(aggSize,clr)
% this one is really the sequence of average momenta
% plotFig = 4;
% momAvg = [42.2964;41.1153;42.0875;41.5578;42.5435;41.9132;40.2426;42.4980;41.3177;42.8827;41.9394;40.3250;40.0651;37.5326;37.4996;39.1918;40.4985;40.1718;39.0108;39.7756;39.3788;37.1139;39.9479;40.1349;38.4678;36.7253;34.7730;40.8269;39.9655;39.5493;40.2808;39.6370;38.1273;41.9592;41.8759;44.2589;42.9165;43.0852;42.8527;42.0199];
% this one is really a set of average energies (from ../newsim1/manyInits)
plotFig = 5;
momAvg = [25.4606;26.7735;26.6858;26.1923;26.5929;26.2111;25.7814;25.8228;25.9716;26.2799;25.4807;25.9138;25.8934;26.5559;26.9727;25.4016;26.6654;26.2584;26.4078;26.2142;25.2606;26.1378;25.2521;26.5894;25.4875;26.5820;25.3646;25.6381;25.3599;26.5136;26.7209;24.2845;25.7262;25.5478;25.3614; 24.1373;26.6495;26.1698;25.7589;25.8821];
sizeMomAvg = size(momAvg);
k = 0;
for j = 1:sizeMomAvg
  if aggSize==1 | mod(j,aggSize)==1
    if k>0, cumMomAvg(k) = cumMomAvg(k)/aggSize; end
    k = k + 1;
    cumMomAvg(k) = 0;
  end % if mod
  cumMomAvg(k) = cumMomAvg(k) + momAvg(j);
end % for k
cumMomAvg(k) = cumMomAvg(k)/aggSize;	% last term
noTerms = sizeMomAvg/aggSize;		% must be integer
sizeCumMomAvg = size(cumMomAvg);
frstMom = 0;
scndMom = 0;
for j = 1:noTerms
  frstMom = frstMom + cumMomAvg(j);
  scndMom = scndMom + cumMomAvg(j)^2;
end % for j
momStats(1) = frstMom/noTerms(1);			% mean
momStats(2) = scndMom/noTerms(1) - momStats(1)^2;	% variance
momStats(3) = sqrt(momStats(2));		% standard deviation
minCumMomAvg = min(cumMomAvg);
maxCumMomAvg = max(cumMomAvg);
noBuck = condif(aggSize==1,10,condif(aggSize==2,5,2));
stepBuck = (maxCumMomAvg - minCumMomAvg)/(noBuck - 1);
histo = zeros(1,noBuck);
for j = 1:sizeCumMomAvg(2);
  if cumMomAvg(j) < minCumMomAvg + stepBuck, histo(1) = histo(1) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 2*stepBuck, histo(2) = histo(2) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 3*stepBuck, histo(3) = histo(3) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 4*stepBuck, histo(4) = histo(4) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 5*stepBuck, histo(5) = histo(5) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 6*stepBuck, histo(6) = histo(6) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 7*stepBuck, histo(7) = histo(7) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 8*stepBuck, histo(8) = histo(8) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 9*stepBuck, histo(9) = histo(9) + 1;
  elseif cumMomAvg(j) < minCumMomAvg + 10*stepBuck, histo(10) = histo(10) + 1;
  else % ignore anything over maxMomAvg
  end % if
end % for j
x = minCumMomAvg:stepBuck:maxCumMomAvg;
figure(plotFig)			% hardwired: will erase previous figure 4 or 5
bar(x,histo,clr)
hold on				% must preface 1st invocation by hold off
% title('Histogram of momentum magnitude averages')
% xlabel('momentum, meV-ps/ns')
title('Histogram of energy averages')
xlabel('energy, meV')
ylabel('# occurrences')

% function variability = FTfluctVar		THM			101111
% Hardwire the Fourier transform magnitudes from FTflcutAgg and add up total
% magnitude as vector length. Each set gives an element of  variability  output
function variability = FTfluctVar
momVar39=[0.0642;0.0148;0.0228;0.0171;0.0085;0.0282;0.0201;0.0106;0.0047;0.0152;0.0157;0.0069;0.0045;0.0111;0.0118;0.0174;0.0061;0.0114;0.0079;0.0098;0.0079;0.0114;0.0061;0.0174;0.0118;0.0111;0.0045;0.0069;0.0157;0.0152;0.0047;0.0106;0.0201;0.0282;0.0085;0.0171;0.0228;0.0148;0.0642]*100/sqrt(40);
momVar19=[0.0448;0.0095;0.0154;0.0081;0.0024;0.0168;0.0113;0.0033;0.0057;0.0035;0.0057;0.0033;0.0113;0.0168;0.0024;0.0081;0.0154;0.0095;0.0448]*100/sqrt(20);
momVar9=[0.0307;0.0068;0.0122;0.0098;0.0013;0.0098;0.0122;0.0068; 0.0307]*100/sqrt(10);;
momVar4=[1.8550;0.8812;0.8812;1.8550]/sqrt(5);
variability(1) = vecLength(momVar39);
variability(2) = vecLength(momVar19);
variability(3) = vecLength(momVar9);
variability(4) = vecLength(momVar4);

% function avgEnergy = manyInits		THM			101111
% call moleculeInit 40 times, 10 molecules eqch, and record average energies
function avgEnergy = manyInits
for j = 1:40
  molData = moleculeInit(10,300,[0,0,5,0,0,40,50],0.05,4);
  sizeMolData = size(molData);
  totEn = 0;
  for k = 1:sizeMolData(1)
    totEn = totEn + molData(k,7);
  end % for k
  avgEnergy(j) = totEn/sizeMolData(1);
end % for j

% function enerIgn = energyHisDis(momenCum,enerIgn)		THM	101116
% finds and plots energy ignorance from momenCum(2)
% in and out: enerIgn, column vector of successive values of energy ignorance
function enerIgn = energyHisDis(momenCum,enerIgn)
enerProb = momenCum(:,2)/sum(momenCum(:,2));	% display test only
sizeEnerProb = size(enerProb);		% display test only
enerIg = 0;
for j = 1: sizeEnerProb(1)
  enerP = enerProb(j);
  enerIg = enerIg - enerP.*condif(enerP==0,1,log(enerP));
end % for j
enerIgn = [enerIgn;enerIg];
sizeEnerIgn = size(enerIgn);		% display test only
figure(6)	% hardwired figure 6 will overwrite any previous figure 6
plot(0:sizeEnerIgn(1)-1,enerIgn)
title('Energy ignorance vs time')
xlabel('time (# collisions)')
ylabel('energy ignorance (nats)')

% function molData = entrSim(N,T,r,M,ab)	THM			101102
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = molecuReInit(N,T,startRange,r,M)	fixed initial config.
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
%	[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg)
%	enerIgn = energyHisDis(momenCum,enerIgn);
% Differs from cumuSim by finding and plotting cumulative energy ignorance
% (entropy).
function molData = entrSim(N,T,r,M,ab)

% initialize
startRange = [0,0,5,0,0,40,50];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
% use one or other of the following two lines:
%molData = molecuReInit(N,T,startRange,r,M)	% display test only
molData = moleculeInit(N,T,startRange,r,M)	% display test only
momenCum = zeros(10,2);	% initialize parameters for momenCumHist
momenAvg = [];		%  ditto
[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg);
enerIgn = energyHisDis(momenCum,[]); % capture and plot initial energy ignorance
momenCum = zeros(10,2);	% reset parameters for momenCumHist
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,1)==0		% accumulate for every N collisions
      [momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg);
      enerIgn = energyHisDis(momenCum,enerIgn);
      momenCum = zeros(10,2);		% reset so accumulates over only 10 coll
    end % if mod(happIndx,N)==0
    if mod(happIndx,stepChunk)==0
      j=1:1000;
      beta = 1/25.0221;			% reciprocal of mean energy
      Zterms = exp(-beta*10*j);		% bucket width bw = 10
      Z = sum(Zterms);
      BoltzIgn = 1 + log(Z)		% display
      hold on
      plot(1:happIndx,1.92*ones(happIndx,1),'r')	% use theor max
      hold off
      enerIgn'				% display
      elapsed = toc;			% elapsed time
      chunkNo = chunkNo + 1;
      beep
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/n '],'s');
      if isempty(reply)
          reply = 'y';
      end
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
      end % if reply
    end % if mod()
  end % if collision
end % while(true)

% function [t,c] = molCollWallWhen(cb,p,M,r,abcd)	THM		101117
% find
%   time of collision, t
%   centre after collision:
%     [a-r;y] for right, [r-a;y] for left, [x;b-r] for top, [x,r-b] for bottom
%     - could use sum of appropriate for corner, but let's default to wall
%       if a tie, then schedule an immediate hit on top or bottom
% given
%   centre of molecule at time 0, column vector cb
%   momentum, column vector p
%   mass (amu), M
%   vector abcd describing box (abcd(1),abcd(2))*(abcd(3),abcd(4))
% uses	v = condif(cond,then,els);
%	z = implies(x,y);
%	found = nonnegrows(matrix);
%	found = minrows(matrix);
% Differs from corresponding routine in newsim1 by testing for diaphragm at y=0.
function [t,c] = molCollWallWhen(cb,p,M,r,abcd)
 m = M*10.36;		% convert from amu to milli-eV (ps/nm)^2
 v = p/m;		% velocity
% distances from location  cb  to wall or middle horizontal diaphragm
 dap = abcd(2) - r - cb(1);	% positive distance to vertical wall
 dav = abcd(1) + r - cb(1);	% negative distance to vertical wall
 dbp = abcd(4) - r - cb(2);	% positive distance to horizontal wall
 dbv = abcd(3) + r - cb(2);	% negative distance to horizontal wall
 db0 = -cb(2);		% NB -ve if above y=0 so needs -ve v(2) to cross
% if distance==0 then depend on sign of  v ; time is dist/v; new molecule pos, c
 record(1,:) = condif(implies(dap==0,v(1)>0),[dap/v(1),abcd(2)-r,cb(2)+v(2)*dap/v(1)],[inf,0,0]);
 record(2,:) = condif(implies(dav==0,v(1)<0),[dav/v(1),abcd(1)+r,cb(2)+v(2)*dav/v(1)],[inf,0,0]);
 record(3,:) = condif(implies(dbp==0,v(2)>0),[dbp/v(2),cb(1)+v(1)*dbp/v(2),abcd(4)-r],[inf,0,0]);
 record(4,:) = condif(implies(dbv==0,v(2)<0),[dbv/v(2),cb(1)+v(1)*dbv/v(2),abcd(3)+r],[inf,0,0]);
 record(5,:) = condif(db0~=0,[db0/v(2),cb(1)+v(1)*db0/v(2),0],[inf,0,0]);
        % if at diapraghm (db0==0) then it has already been processed
 next = minrows(nonnegrows(record));	% 2 identical if corner, else 1
 sizeNext = size(next);			% display test only
 t = next(1,1);			% time is smallest of the 5 times
 c = [next(1,2);next(1,3)];	% new position of molecule 4 corresponding event

% function [p,cntB] = molCollWallCountBot(pb,tmult,bmult,abcd,r,c,cntB,mix)
%								THM	101117
% (initial version, extracted from final)
% given vectors momentum pb, box boundaries abcd, position c; scalars radius r,
%  integer count cntB, boolean mix (0 if y=0 diaphragm closed and gases mix;
%  1 if diaphragm open and gases don't mix.
%  The multipliers tmult, bmult change top, bottom momenta due to moving wall,
%	heat, respectively. (Set to 1 for no heat transfer, fixed volume.)
% find new momentum p
% Differs from same in newsim1 by interaction with y=0 diaphragm, by counting
%  number of collisions with bottom wall, and by allowing momentum multipliers
%  at top and bottom.
function p = molCollWallCountBot(pb,tmult,bmult,abcd,r,c,cntB,mix)
% tmult = 1; bmult = 1; cntB = 0;		% for future refinement
abr = abcd - [-r,r,-r,r];	% extend wall to _centre_ of molecule
p = pb;				% initialize: momentum out = momentum in
if c(1) < abr(1) | c(1) > abr(2) | c(2) < abr(3) | c(2) > abr(4)
  display(['molCollWallCountBot: ' num2str(c') ' out of box ' num2str(abr)])
elseif (c(1)==abr(1) | c(1)==abr(2)) & (c(2)==abr(3) | c(2)==abr(4)), p = -pb;
					% 4 corners: reverse momentum
elseif (c(1)==abr(1) | c(1)==abr(2)) & c(2) == 0, p = -pb; % diaphragm ends:   "
elseif c(1)==abr(1) | c(1)==abr(2), p(1) = -pb(1);%side wall: reverse x-momentum
elseif c(2) == abr(4), p(2) = -tmult^1.5*pb(2);%top: (approx) reverse y-momentum
			p(1) = tmult^.5*pb(1);
elseif c(2) == abr(3), p(2) = -bmult*pb(2);	%bot: default reverse y-momentum
			p(1) = bmult*pb(1);
			cntB = cntB + 1;
elseif c(2) == 0
  if mix, p = pb;		% diaphragm open: default keep momentum
  else p(2) = -pb(2);		% diaphragm closed: reverse y-momentum
  end % if mix
else display('molCollWallCountBot: no wall collision')
end %if

% 101117
% >> p = molCollWallCountBot([0;1],1,1,[-20,20,-10,10],.05,[0;0],0,1) 
% p =  0
%      1 
% >> p = molCollWallCountBot([0;1],1,1,[-20,20,-10,10],.05,[0;0],0,0) 
% p =  0
%     -1

% error on l. 127? : if executes only when happIndx==1	110223
% function molData = tmptureSim(N,T,r,M,ab)	THM			101118
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% N,T,r,M 2*1 column vectors to accommodate 2 gases
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = molecuReInit(N,T,startRange,r,M)	fixed initial config.
%    or	molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
%	[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg)
%	enerIgn = energyHisDis(momenCum,enerIgn);
% Differs from entrSim by allowing 2 gases in upper and lower half of box,
%  and possibility of removing diaphragm separating them (say after initial
%  equilibrium reached); uses entrSim's entropy routine and. like it plots
%  entropy in steps of 1. Instead of using cumuSim's molDataDistr(), the
%  momentum magnitude histograms are plotted directly from the main program.
% (A subsequent comparison is done of the results with theory by
%	[pAvg,pStdev] = plotMaxwell(T,M) )
function molData = tmptureSim(N,T,r,M,ab)

% initialize
startRange1 = [0,0,5,0,0,40,50];
startRange2 = [0,0,5,0,0,-50,-40];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
% use one or other of the following two lines:
%molData = molecuReInit(N,T,startRange,r,M)	% display test only
molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))   % display test only
molData2 = moleculeInit(N(2),T(2),startRange2,r(2),M(2))   % display test only
molData = [molData1;molData2];
momenCum = zeros(10,2);	% initialize parameters for momenCumHist
momenAvg = [];		%  ditto
[momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg);
enerIgn = energyHisDis(momenCum,[]); % capture and plot initial energy ignorance
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
mix = 0;		% initially don't mix the gases in top and bottom
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
%   if mod(happIndx,max(N))==0		% accumulate for every N collisions
    if mod(happIndx,1==0)		% snapshot every collisions
      [momenCum,momenAvg] = momenCumHisto(molData,momenCum,momenAvg);
      enerIgn = energyHisDis(momenCum,enerIgn);
      momenCumDistr(:,1) = momenCum(:,1)/sum(momenCum(:,1));	% momMagn distr
      figure(8)		% hardwired: will overwrite any existing figure 8
      j=1:10;
      bw = 10;
      plot(bw*j,momenCumDistr(:,1))
      title('cumulative momentum magn.')
      xlabel('momentum, meV-ps/nm')
      ylabel('probability')
      momenCum = zeros(10,2);		% reset so accumulates over only 10 coll
    end % if mod(happIndx,N)==0
    if mod(happIndx,stepChunk)==0
      enerIgn'				% display
      elapsed = toc;			% elapsed time
      chunkNo = chunkNo + 1;
      beep
      avgEnergy1 = sum(molData(1:N(1),7))/N(1);
      avgEnergy2 = sum(molData(N(1)+1:N(1)+N(2),7))/N(2);
      energyX = (molData(:,3).^2./(2*10.36*molData(:,6)));
      avgEnergyX = sum(energyX)/(N(1)+N(2));	% check equipartition
      energyY = (molData(:,4).^2./(2*10.36*molData(:,6)));
      avgEnergyY = sum(energyY)/(N(1)+N(2));
      disp(['Average energies: gas 1 ' num2str(avgEnergy1) ' gas 2 ' ...
	num2str(avgEnergy2) ' x partition ' num2str(avgEnergyX) ...
	' y partition ' num2str(avgEnergyY)])
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/m[mix]/n '],'s');
      if isempty(reply)
	reply = 'y';
      end % if isempty
      if reply=='m'			% toggle mixing gases
	mix = ~mix;
	reply = 'y';
      end % if reply==
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
      end % if reply~=
    end % if mod()
  end % if collision
end % while(true)

% function smooth2enerIgn(runlen)		THM			101118
% ruunig average smoothing of energy ignorance found by ../newsim2/tmptureSim()
% input  runlen  length of smoothing runs
function smooth2enerIgn(runlen)
enerIgn1 =...	% 72 lines
[0.9797; 0.9797; 0.9896; 0.9797; 0.9687; 0.9687; 0.9687;...
0.9797; 1.0287; 1.0287; 1.0287; 1.0287; 1.0287; 1.0177;...
1.0177; 1.0177; 1.0056; 1.0056; 1.0056; 1.0056; 1.0056;...
1.0056; 1.0056; 1.0056; 1.0056; 1.0056; 1.0056; 1.0056;...
1.0056; 1.0056; 1.0056; 1.0056; 1.0056; 1.0056; 1.0056;...
1.0056; 1.0056; 1.0056; 1.0056; 1.0406; 1.0406; 1.0406;...
1.0406; 1.0406; 1.0406; 1.0406; 1.0406; 1.0406; 1.0406;...
1.0406; 1.0406; 1.0406; 1.0406; 1.0406; 1.0406; 1.0406;...
1.0406; 1.0406; 1.0406; 1.0273; 1.0273; 1.0273; 1.0273;...
1.0273; 1.0273; 1.0273; 1.0871; 1.0871; 1.1602; 1.2374;...
1.2929; 1.2929; 1.3236; 1.3700; 1.3700; 1.3647; 1.3507;...
1.3740; 1.3902; 1.3816; 1.4147; 1.3979; 1.4034; 1.3694;...
1.3577; 1.3330; 1.3330; 1.3635; 1.3724; 1.3753; 1.3753;...
1.3648; 1.3878; 1.3799; 1.3925; 1.3920; 1.3611; 1.3733;...
1.3560; 1.3918; 1.4063; 1.4231; 1.4286; 1.4477; 1.4477;...
1.4697; 1.4925; 1.4832; 1.4936; 1.4680; 1.4680; 1.4642;...
1.4642; 1.4642; 1.4733; 1.4783; 1.4822; 1.4609; 1.4609;...
1.4609; 1.4426; 1.4426; 1.4347; 1.4347; 1.4347; 1.4563;...
1.4563; 1.4531; 1.4498; 1.4267; 1.4699; 1.4926; 1.4789;...
1.4873; 1.4873; 1.4873; 1.4699; 1.4699; 1.4827; 1.4845;...
1.4827; 1.4842; 1.4640; 1.4535; 1.4523; 1.4523; 1.4275;...
1.4462; 1.4462; 1.4462; 1.4456; 1.4657; 1.4614; 1.4614;...
1.4614; 1.4718; 1.4718; 1.4963; 1.4963; 1.4963; 1.4991;...
1.5018; 1.4965; 1.4937; 1.4937; 1.4965; 1.4408; 1.4408;...
1.4408; 1.4489; 1.4330; 1.4315; 1.4315; 1.4366; 1.4344;...
1.4309; 1.4363; 1.4152; 1.4179; 1.4179; 1.4179; 1.4179;...
1.3943; 1.3943; 1.3825; 1.3825; 1.3599; 1.3632; 1.3540;...
1.3605; 1.3522; 1.3285; 1.3522; 1.3522; 1.3522; 1.3757;...
1.3757; 1.3757; 1.3757; 1.3757; 1.3757; 1.3757; 1.3757;...
1.3757; 1.3975; 1.4178; 1.4368; 1.4545; 1.4580; 1.4806;...
1.4806; 1.4806; 1.4979; 1.5141; 1.5141; 1.5088; 1.5088;...
1.5230; 1.5364; 1.5488; 1.5565; 1.5482; 1.5482; 1.5482;...
1.5482; 1.5482; 1.5353; 1.5353; 1.5353; 1.5353; 1.5511;...
1.5511; 1.5596; 1.5596; 1.5547; 1.5547; 1.5547; 1.5547;...
1.5547; 1.5547; 1.5694; 1.5694; 1.5694; 1.5547; 1.5457;...
1.5604; 1.5569; 1.5569; 1.5422; 1.5542; 1.5671; 1.5671;...
1.5671; 1.5671; 1.5671; 1.5792; 1.5792; 1.5792; 1.5903;...
1.5903; 1.5513; 1.5513; 1.5513; 1.5611; 1.5702; 1.5702;...
1.5702; 1.5702; 1.5702; 1.5702; 1.5702; 1.5611; 1.5650;...
1.5650; 1.5650; 1.5650; 1.5650; 1.5657; 1.5727; 1.5721;...
1.5721; 1.5630; 1.5593; 1.5593; 1.5593; 1.5593; 1.5593;...
1.5593; 1.5649; 1.5664; 1.5664; 1.5937; 1.5937; 1.5937;...
1.5918; 1.5889; 1.5889; 1.5738; 1.5738; 1.5738; 1.5738;...
1.5738; 1.5498; 1.5392; 1.5229; 1.5229; 1.5229; 1.5285;...
1.5285; 1.5285; 1.5377; 1.5438; 1.5438; 1.5285; 1.5269;...
1.5199; 1.5199; 1.5199; 1.5199; 1.5173; 1.5173; 1.5173;...
1.5173; 1.5173; 1.5280; 1.5335; 1.5335; 1.5433; 1.5433;...
1.5727; 1.5727; 1.5727; 1.5727; 1.5774; 1.5952; 1.5949;...
1.5949; 1.5546; 1.5546; 1.5546; 1.5546; 1.5546; 1.6011;...
1.6011; 1.6011; 1.6011; 1.5931; 1.5973; 1.5973; 1.5893;...
1.5893; 1.5468; 1.5468; 1.5650; 1.5738; 1.5588; 1.5588;...
1.5588; 1.5674; 1.5625; 1.5452; 1.5452; 1.5452; 1.5684;...
1.5684; 1.5789; 1.5938; 1.5903; 1.5903; 1.5994; 1.6078;...
1.6078; 1.6537; 1.6537; 1.6449; 1.6449; 1.6353; 1.6449;...
1.6578; 1.6685; 1.6685; 1.6685; 1.6657; 1.6525; 1.6525;...
1.6571; 1.6571; 1.6571; 1.6468; 1.6468; 1.6468; 1.6647;...
1.6647; 1.6637; 1.6625; 1.6652; 1.6652; 1.6193; 1.6297;...
1.6297; 1.6297; 1.6377; 1.6390; 1.6368; 1.6368; 1.5987;...
1.5873; 1.5873; 1.5948; 1.5990; 1.6206; 1.6206; 1.6489;...
1.6365; 1.6365; 1.6365; 1.6365; 1.6365; 1.6365; 1.6136;...
1.6011; 1.5934; 1.5934; 1.6214; 1.6214; 1.6214; 1.6214;...
1.6342; 1.6382; 1.6198; 1.5935; 1.5952; 1.5891; 1.5891;...
1.5891; 1.5769; 1.6152; 1.6152; 1.6021; 1.6021; 1.6483;...
1.5966; 1.5945; 1.5945; 1.5945; 1.5945; 1.6001; 1.6047;...
1.6278; 1.6638; 1.6638; 1.6513; 1.6101; 1.6307; 1.6455;...
1.6440; 1.6440; 1.6564; 1.6564; 1.6491; 1.6591; 1.6411;...
1.6022; 1.5788; 1.5504; 1.5628; 1.5785; 1.5934; 1.5934;...
1.5563; 1.5594; 1.5632; 1.5720; 1.5673; 1.5673; 1.5700;...
1.5700; 1.5700; 1.5623; 1.5797; 1.5951; 1.6013; 1.6013;...
1.6013; 1.6013; 1.6013; 1.6013; 1.5903; 1.5903; 1.5903;...
1.5903; 1.5903; 1.5903; 1.5868; 1.5947; 1.5718; 1.5718;...
1.5718; 1.5862; 1.6073; 1.6073];
top = 501 - 1 - runlen;
for j = 1:top
  accum = 0;
  for k = 1:runlen
  % cleverer code would initialize accum array then replace 1 value at a time
    accum = accum + enerIgn1(j+k-1);
  end % for k
  enerApp1(j) = accum/runlen;
end % for j
figure(13)
plot(1:501,enerIgn1,'b',1+runlen/2:top+runlen/2,enerApp1,'r')
title('smooth2EnerIgn1')
xlabel('time (# collisions)')
ylabel('energy ignorance before mixing starts')
enerIgn2=...	% 72 lines
[1.6073; 1.6073; 1.6054;...
1.5763; 1.5763; 1.5796; 1.5796; 1.5701; 1.5701; 1.5701;...
1.5426; 1.5517; 1.5517; 1.5601; 1.6010; 1.6010; 1.6110;...
1.6110; 1.6110; 1.6571; 1.6571; 1.6571; 1.7058; 1.6921;...
1.6921; 1.7245; 1.7200; 1.7519; 1.7545; 1.7483; 1.7396;...
1.6843; 1.6843; 1.7002; 1.6783; 1.6883; 1.6783; 1.6745;...
1.6511; 1.6661; 1.6661; 1.6661; 1.6564; 1.6564; 1.6564;...
1.6564; 1.6564; 1.6564; 1.6754; 1.6754; 1.6754; 1.6866;...
1.6784; 1.6774; 1.6942; 1.7034; 1.7034; 1.7122; 1.7069;...
1.7364; 1.7364; 1.7364; 1.7477; 1.7477; 1.7477; 1.7477;...
1.7384; 1.7301; 1.7321; 1.7321; 1.6935; 1.6996; 1.7078;...
1.7197; 1.7188; 1.7188; 1.7122; 1.7122; 1.7122; 1.7076;...
1.7076; 1.7390; 1.7361; 1.7416; 1.7374; 1.7463; 1.7374;...
1.7374; 1.7299; 1.7220; 1.7153; 1.6959; 1.6959; 1.6959;...
1.6959; 1.6959; 1.7102; 1.7070; 1.7070; 1.7228; 1.7319;...
1.7345; 1.7395; 1.7395; 1.7310; 1.7310; 1.7398; 1.7429;...
1.7817; 1.7980; 1.8116; 1.8116; 1.8163; 1.8393; 1.8483;...
1.8393; 1.8288; 1.8288; 1.8197; 1.8293; 1.8293; 1.8255;...
1.8255; 1.8255; 1.8295; 1.8295; 1.8304; 1.8304; 1.8388;...
1.8388; 1.8408; 1.8408; 1.8463; 1.8463; 1.8463; 1.8463;...
1.8408; 1.8481; 1.8481; 1.8456; 1.8465; 1.8465; 1.8465;...
1.8465; 1.8428; 1.8353; 1.8361; 1.8361; 1.8361; 1.8354;...
1.8073; 1.8327; 1.8333; 1.8333; 1.8308; 1.8369; 1.8389;...
1.7934; 1.7900; 1.7950; 1.7942; 1.7615; 1.7615; 1.8145;...
1.8145; 1.8118; 1.8118; 1.8118; 1.8099; 1.8099; 1.8238;...
1.8238; 1.8152; 1.8152; 1.8190; 1.8120; 1.8514; 1.8533;...
1.8527; 1.8527; 1.8541; 1.8541; 1.8527; 1.8540; 1.8484;...
1.8519; 1.8448; 1.8376; 1.8410; 1.8410; 1.8363; 1.8363;...
1.8363; 1.8298; 1.8298; 1.8224; 1.7900; 1.7769; 1.7811;...
1.7811; 1.7697; 1.7557; 1.7636; 1.7591; 1.7591; 1.7904;...
1.7904; 1.7904; 1.7910; 1.7786; 1.7786; 1.7515; 1.7555;...
1.7736; 1.7682; 1.7682; 1.7691; 1.7691; 1.7691; 1.7587;...
1.7587; 1.7560; 1.7671; 1.7772; 1.7801; 1.7788; 1.7284;...
1.7293; 1.7198; 1.7158; 1.7146; 1.6848; 1.6956; 1.6963;...
1.6865; 1.7001; 1.7333; 1.7340; 1.7394; 1.7789; 1.7937;...
1.8022; 1.8098; 1.8046; 1.7867; 1.7867; 1.7960; 1.7960;...
1.7960; 1.7919; 1.7907; 1.7907; 1.7907; 1.7907; 1.7986;...
1.7958; 1.7958; 1.7931; 1.7931; 1.7924; 1.7924; 1.7852;...
1.7852; 1.7898; 1.7819; 1.7886; 1.7863; 1.7776; 1.8022;...
1.8097; 1.8175; 1.8175; 1.8048; 1.8078; 1.8076; 1.8076;...
1.8076; 1.8178; 1.8184; 1.8184; 1.8184; 1.8080; 1.8089;...
1.8056; 1.8033; 1.7978; 1.7978; 1.8136; 1.8136; 1.8148;...
1.8212; 1.8212; 1.8212; 1.8190; 1.8225; 1.8158; 1.8069;...
1.8134; 1.8128; 1.8128; 1.8128; 1.8128; 1.8049; 1.8049;...
1.8198; 1.8188; 1.8188; 1.8188; 1.8209; 1.8209; 1.8209;...
1.8209; 1.8206; 1.8206; 1.8209; 1.8108; 1.8174; 1.8121;...
1.8121; 1.7868; 1.7636; 1.7690; 1.7636; 1.7703; 1.7703;...
1.7688; 1.7740; 1.7740; 1.7740; 1.8207; 1.8207; 1.8224;...
1.8154; 1.8052; 1.8052; 1.7985; 1.7996; 1.7986; 1.8085;...
1.8085; 1.8085; 1.8098; 1.8180; 1.8210; 1.8225; 1.8172;...
1.8181; 1.8181; 1.8188; 1.8269; 1.8202; 1.8249; 1.8233;...
1.8233; 1.8233; 1.8068; 1.8141; 1.8141; 1.8141; 1.8068;...
1.8074; 1.8097; 1.8097; 1.8082; 1.8096; 1.8003; 1.8003;...
1.8003; 1.7966; 1.8145; 1.7950; 1.7950; 1.7950; 1.7950;...
1.8049; 1.7950; 1.7950; 1.7950; 1.7950; 1.8010; 1.8124;...
1.8085; 1.8085; 1.8240; 1.8206; 1.8206; 1.8200; 1.8116;...
1.8116; 1.8473; 1.8800; 1.8800; 1.8800; 1.8800; 1.8800;...
1.8874; 1.8824; 1.8824; 1.9067; 1.9067; 1.9067; 1.9067;...
1.9019; 1.8891; 1.8891; 1.8674; 1.8763; 1.8763; 1.8727;...
1.8760; 1.8760; 1.8850; 1.8850; 1.8876; 1.8968; 1.9043;...
1.9043; 1.9067; 1.9126; 1.9126; 1.9093; 1.9103; 1.9103;...
1.9326; 1.9326; 1.9318; 1.9318; 1.9302; 1.9302; 1.9293;...
1.9293; 1.9313; 1.9313; 1.9313; 1.9313; 1.9319; 1.9327;...
1.9267; 1.9335; 1.9314; 1.9350; 1.9164; 1.9164; 1.9164;...
1.8789; 1.8781; 1.8791; 1.8768; 1.8782; 1.8782; 1.8759;...
1.8759; 1.8742; 1.8729; 1.8729; 1.8729; 1.8729; 1.8772;...
1.8230; 1.8230; 1.8096; 1.8043; 1.8043; 1.8069; 1.8083;...
1.8083; 1.8060; 1.8060; 1.7975; 1.8151; 1.8038; 1.8182;...
1.8247; 1.8069; 1.8069; 1.8069; 1.8069; 1.8069; 1.7985;...
1.7964; 1.8224; 1.8084; 1.8172; 1.8172; 1.8148; 1.8115;...
1.8115; 1.8362; 1.8690; 1.8675; 1.8602; 1.8612; 1.8641;...
1.8675; 1.8713; 1.8724; 1.8750; 1.8750; 1.8750; 1.8764];
top = 500 - 1 - runlen;
for j = 1:top
  accum = 0;
  for k = 1:runlen
  % cleverer code would initialize accum array then replace 1 value at a time
    accum = accum + enerIgn2(j+k-1);
  end % for k
  enerApp2(j) = accum/runlen;
end % for j
figure(14)
plot(1:500,enerIgn2,'b',1+runlen/2:top+runlen/2,enerApp2,'r')
title('smooth2EnerIgn2')
xlabel('time (# collisions)')
ylabel('energy ignorance after mixing starts')
figure(15)
plot(1:1001,[enerIgn1;enerIgn2],'b',1+runlen/2:500-runlen/2, enerApp1,'r',502+runlen/2:1000-runlen/2,enerApp2,'r')

% function molData = presSim(N,T,r,M,ab)	THM			101124
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = moleculeInit(N,T,startRange,r,M)
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
%	molDatAverage = molDataHisto(molData,[]);
% Differs from statSim() by plotting rates of change of momentum per unit side;
% also avoids first 100 collisions.
function molData = presSim(N,T,r,M,ab)

% initialize
startRange = [0,0,5,0,0,40,50];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
molData = moleculeInit(N,T,startRange,r,M)	% display test only
% molDatAverage = molDataHisto(molData,[]);
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
oldTime = 0;
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
totTop = 0; numTop = 0;	% initialize momentum counting accumulators
totBot = 0; numBot = 0;	% initialize momentum counting accumulators
totRgt = 0; numRgt = 0;	% initialize momentum counting accumulators
totLft = 0; numLft = 0;	% initialize momentum counting accumulators
pressure = [];
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % distinguish collision on top, bottom, right, left sides and accumulate
    if deltaPx1==0
      if deltaPy1<0
	totTop = totTop + deltaPy1;
	numTop = numTop + 1;
      else % deltaPy1>=0 and the == doesn't matter
	totBot = totBot + deltaPy1;
	numBot = numBot + 1;
      end % if deltaPy1<0
    end %if deltaPx1==0
    if deltaPy1==0
      if deltaPx1<0
	totRgt = totRgt + deltaPx1;
	numRgt = numRgt + 1;
      else % deltaPx1>=0 and the == doesn't matter
	totLft = totLft + deltaPx1;
	numLft = numLft + 1;
      end % if deltaPx1<0
    end %if deltaPy1==0
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,stepChunk)==0
      elapsed = toc;				% elapsed time
      chunkNo = chunkNo + 1;
      if firstChunk
	firstChunk = false;
      end % if firstChunk
      % molDatAverage = molDataHisto(molData,molDatAverage);
      beep
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/n '],'s');
      if isempty(reply)
          reply = 'y';
      end
      if reply~='y'	% not 'y'
	pressure = [pressure;[totTop/a/t,totBot/a/t,totRgt/b/t,totLft/b/t]];
	pressure				% display pressure
	sizePressure = size(pressure);
	P = sizePressure(1);
	figure(16)			% hardwired: will overwrite any fig 16
	plot(1:P,pressure(:,1),'b',1:P,pressure(:,2),'g',1:P,pressure(:,3),'r',1:P,pressure(:,4),'m')
	title('pressures on four sides')
	xlabel(['chunks of ' num2str(stepChunk) ' intermol coll'])
	ylabel('pressure (meV/nm^2)')
	% NB 3-D pressure is meV/nm^3 = 1.6 atm (1 atm = 101325 Pa (J/m^3) and
	%  conversion meV = 1.602 176 53*10^-22 J)
	legend('top','bottom','right','left','Location','East')
        break
      else tic					% elapsed time
	t = time - oldTime;
	a = ab(1);
	b = ab(2);
	pressure = [pressure;[totTop/a/t,totBot/a/t,totRgt/b/t,totLft/b/t]];
	totTop = 0; numTop = 0;	% reset momentum counting accumulators
	totBot = 0; numBot = 0;	% reset momentum counting accumulators
	totRgt = 0; numRgt = 0;	% reset momentum counting accumulators
	totLft = 0; numLft = 0;	% reset momentum counting accumulators
	oldTime = time;
      end % if reply
    end % if mod()
  end % if collision
end % while(true)

% function molData = press2Sim(N,T,r,M,ab)	THM			101118
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% N,T,r,M 2*1 column vectors to accommodate 2 gases
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = molecuReInit(N,T,startRange,r,M)	fixed initial config.
%    or	molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
% Differs from tmptureSim by tracking the pressures of the two gases before and
% after mixing: see ../newsim1/presSim(). Does not record energy stats.
function molData = press2Sim(N,T,r,M,ab)

% initialize
startRange1 = [0,0,5,0,0,40,50];
startRange2 = [0,0,5,0,0,-50,-40];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
% use one or other of the following two lines:
%molData = molecuReInit(N,T,startRange,r,M)	% display test only
molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))   % display test only
molData2 = moleculeInit(N(2),T(2),startRange2,r(2),M(2))   % display test only
molData = [molData1;molData2];
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
oldTime = 0.0;
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
mix = 0;		% initially don't mix the gases in top and bottom
totTop = 0; numTop = 0;	% initialize momentum counting accumulators
totBot = 0; numBot = 0;	% initialize momentum counting accumulators
pressure = [];
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % distinguish collision on top for gas 1, bottom for gas 2 and accumulate
    if deltaPx1==0
      if deltaPy1<0
	if v1<=N(1)			% molecule belongs to upper gas (1)
	  totTop = totTop + deltaPy1;
	  numTop = numTop + 1;
	end % if v1<=N(1)
      else % deltaPy1>=0 and the == doesn't matter
	if v1>N(1)			% molecule belongs to lower gas (2)
	  totBot = totBot + deltaPy1;
	  numBot = numBot + 1;
	end % if v1>N(1)
      end % if deltaPy1<0
    end %if deltaPx1==0
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,stepChunk)==0
      elapsed = toc;			% elapsed time
      chunkNo = chunkNo + 1;
      beep
      avgEnergy1 = sum(molData(1:N(1),7))/N(1);
      avgEnergy2 = sum(molData(N(1)+1:N(1)+N(2),7))/N(2);
      energyX = (molData(:,3).^2./(2*10.36*molData(:,6)));
      avgEnergyX = sum(energyX)/(N(1)+N(2));	% check equipartition
      energyY = (molData(:,4).^2./(2*10.36*molData(:,6)));
      avgEnergyY = sum(energyY)/(N(1)+N(2));
      disp(['Average energies: gas 1 ' num2str(avgEnergy1) ', gas 2 ' ...
	num2str(avgEnergy2) ', x partition ' num2str(avgEnergyX) ...
	', y partition ' num2str(avgEnergyY)])
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/m[mix]/n '],'s');
      if isempty(reply)
	reply = 'y';
      end % if isempty
      if reply=='m'			% toggle mixing gases
	mix = ~mix;
	reply = 'y';
      end % if reply==
      if reply~='y'	% not 'y'
	pressure = [pressure;[-totTop/a/t,totBot/a/t]];
	pressure				% display pressure
	sizePressure = size(pressure);
	P = sizePressure(1);
        break
      else tic					% elapsed time
	t = time - oldTime;
	a = ab(1);
	b = ab(2);
	pressure = [pressure;[-totTop/a/t,totBot/a/t]];
	sizePressure = size(pressure);
	P = sizePressure(1);
	figure(17)			% hardwired: will overwrite any fig 17
	plot(1:P,pressure(:,1),'b',1:P,pressure(:,2),'g')
	title('pressures of upper and lower gases')
	xlabel(['chunks of ' num2str(stepChunk) ' intermol coll'])
	ylabel('pressure (meV/nm^2)')
	% NB 3-D pressure is meV/nm^3 = 1.6 atm (1 atm = 101325 Pa (J/m^3) and
	%  conversion meV = 1.602 176 53*10^-22 J)
	legend('upper','lower','Location','West')
	totTop = 0; numTop = 0;	% reset momentum counting accumulators
	totBot = 0; numBot = 0;	% reset momentum counting accumulators
	oldTime = time;
      end % if reply~=
    end % if mod()
  end % if collision
end % while(true)

% function molData = chmpotSim(N,T,r,M,ab)	THM			101118
% N molecules each of radius r (nm), mass M (AMU) at temperature T (degK)
% N,T,r,M 2*1 column vectors to accommodate 2 gases
% Helium 0.049nm (1), 4AMU; Neon 0.051 m (1), 20AMU; Argon 0.088nm (1.8), 40AMU)
% find; molecules in box [-ab(1),ab(1)]x[-ab(2),ab(2)] nanometers
%	(initially symmetrical, stored abcd [abcd(1),abcd(2)]x[abcd(3),abcd(4)])
% Return molData
% uses	molData = molecuReInit(N,T,startRange,r,M)	fixed initial config.
%    or	molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))
%	[delTime,centre] = molCollWallWhen(cb,p,M,r,ab);
%	[delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M,M,r,r);
%	p1= molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
%	[p1,p2] = moleculeCollide(M,M,p1b,p2b,0,C12);
% Differs from tmptureSim, press2Sim by tracking the centres of masses of the
% two gases before and after mixing
function molData = chmpotSim(N,T,r,M,ab)

% initialize
startRange1 = [0,0,5,0,0,40,50];
startRange2 = [0,0,5,0,0,-50,-40];
%	      l h s x y  l h	s is stdev in nm of spread along line of angle
%	      ang   cntr	from ang_l to ang_h centred at x,y
%	     ----pos---  mom	mom_l to mom_h is angle of motion direction
% for box -20:20*-10:10 try exactly 45 degrees from exactly (0,0)
% generates molData[N * cx,cy,px,py,r,M,E]
%			 1  2  3  4 5 6 7
% L: nm   T: ps  M: meV(ps/nm)^2   L/T: nm/ps   ML/T: meV(ps/nm)
% use one or other of the following two lines:
%molData = molecuReInit(N,T,startRange,r,M)	% display test only
molData1 = moleculeInit(N(1),T(1),startRange1,r(1),M(1))   % display test only
molData2 = moleculeInit(N(2),T(2),startRange2,r(2),M(2))   % display test only
molData = [molData1;molData2];
oldMolData = molData;
sizeMolData = size(molData);
noVals = sizeMolData(1);
abcd(1) = -ab(1); abcd(2) = ab(1); abcd(3) = -ab(2); abcd(4) = ab(2);
happIndx = 0;		% keep track of number of steps
time = 0.0;		% keep track of time
stepChunk = 100;	% iterate this many steps then check if more wanted
firstChunk = true;	% to detect first  collisions at resume time
%stepChunk = 1;		% test only
chunkNo = 0;
mix = 0;		% initially don't mix the gases in top and bottom
CofM = [];
tic					% elapsed time

% Loop starts here
while(true)
  collision = false;
  % find time of next collision
  record = [];				% record of collision times, results
  for v1 = 1:noVals
    c1b = [molData(v1,1); molData(v1,2)];
    p1b = [molData(v1,3); molData(v1,4)];
    M1 = molData(v1,6);
    r1 = molData(v1,5);
    [delTime,centre] = molCollWallWhen(c1b,p1b,M1,r1,abcd);  % display test only
    record = [record;[delTime,v1,v1,centre(1),centre(2),centre(1),centre(2)]];
    for v2 = v1+1:noVals
      c2b = [molData(v2,1); molData(v2,2)];
      p2b = [molData(v2,3); molData(v2,4)];
      M2 = molData(v2,6);
      r2 = molData(v2,5);
      [delTime,cntr1,cntr2] = moleculeCollWhen(c1b,c2b,p1b,p2b,M1,M2,r1,r2);
      record = [record;[delTime,v1,v2,cntr1(1),cntr1(2),cntr2(1),cntr2(2)]];
    end % for v2
  end % for v1

  %sqrt choose and execute next collision
  next = minrows(record);	% smallest delTime wins  display test only
  time = time + next(1);
  v1 = next(2);
  v2 = next(3);
  c1 = [next(4);next(5)];
  c2 = [next(6);next(7)];
  deltaX1 = c1(1) - molData(v1,1);
  deltaY1 = c1(2) - molData(v1,2);
  deltaX2 = c2(1) - molData(v2,1);
  deltaY2 = c2(2) - molData(v2,2);
  r1 = molData(v1,5);
  r2 = molData(v2,5);
  M1 = molData(v1,6);
  M2 = molData(v2,6);
  p1b = [molData(v1,3); molData(v1,4)];
  p2b = [molData(v2,3); molData(v2,4)];
  if v1==v2				% collision is with wall
    p1 = molCollWallCountBot(p1b,1,1,abcd,r1,c1,0,mix);
    deltaPx1 = p1(1) - p1b(1);		% change of momentum at wall
    deltaPy1 = p1(2) - p1b(2);
    % molData for v1 is common to both these branches: done afterwards
  else % v1~=v2
    collision = true;			% test only: used to update afterColl
    C12 = c2 - c1;
    [p1,p2] = moleculeCollide(M1,M2,p1b,p2b,0,C12);	% display test only
    molData(v2,1) = c2(1);
    molData(v2,2) = c2(2);
    molData(v2,3) = p2(1);
    molData(v2,4) = p2(2);
    molData(v2,7) = (p2(1).^2 + p2(2).^2)/(2*M2*10.36);		% energy
  end % if v1==v2
  molData(v1,1) = c1(1);
  molData(v1,2) = c1(2);
  molData(v1,3) = p1(1);
  molData(v1,4) = p1(2);
  molData(v1,7) = (p1(1).^2 + p1(2).^2)/(2*M1*10.36);		% energy
  for v = 1:noVals			% update all other molecules' positions
    if v==v1 | v==v2, continue, end % if
    deltaX = molData(v,3)/(molData(v,6)*10.36)*next(1);
    deltaY = molData(v,4)/(molData(v,6)*10.36)*next(1);
    molData(v,1) = molData(v,1) + deltaX;	% update position
    molData(v,2) = molData(v,2) + deltaY;
  end % for v
  if collision
    happIndx = happIndx + 1;
    if mod(happIndx,stepChunk)==0
      elapsed = toc;			% elapsed time
      chunkNo = chunkNo + 1;
      beep
      avgEnergy1 = sum(molData(1:N(1),7))/N(1);
      avgEnergy2 = sum(molData(N(1)+1:N(1)+N(2),7))/N(2);
      energyX = (molData(:,3).^2./(2*10.36*molData(:,6)));
      avgEnergyX = sum(energyX)/(N(1)+N(2));	% check equipartition
      energyY = (molData(:,4).^2./(2*10.36*molData(:,6)));
      avgEnergyY = sum(energyY)/(N(1)+N(2));
      disp(['Average energies: gas 1 ' num2str(avgEnergy1) ', gas 2 ' ...
	num2str(avgEnergy2) ', x partition ' num2str(avgEnergyX) ...
	', y partition ' num2str(avgEnergyY)])
      reply = input([num2str(elapsed) ' elapsed, ' num2str(time) ' ps.: another ' num2str(stepChunk) ' collisions? y/m[mix]/n '],'s');
      if isempty(reply)
	reply = 'y';
      end % if isempty
      if reply=='m'			% toggle mixing gases
	mix = ~mix;
	reply = 'y';
      end % if reply==
      if reply~='y'	% not 'y'
        break
      else tic					% elapsed time
	N1 = N(1);
	N2 = N(2);
	CofM1 = [sum(molData(1:N1,1)),sum(molData(1:N1,2))]/N1;
	CofM2 = [sum(molData(N1+1:N1+N2,1)),sum(molData(N1+1:N1+N2,2))]/N2;
	CofM = [CofM;[CofM1,CofM2]];
	sizeCofM = size(CofM);
	C = sizeCofM(1);
	figure(18)			% hardwired: will overwrite any fig 18
%	plot(1:C,CofM(:,1),'b',1:C,CofM(:,2),'g',1:C,CofM(:,3),'r',1:C,CofM(:,4),'m')
	plot(1:C,CofM(:,2),'b',1:C,CofM(:,4),'r')
	title('centres of mass of upper and lower gases')
	xlabel(['chunks of ' num2str(stepChunk) ' intermol coll'])
	ylabel('centres of mass (nm)')
	% NB 3-D pressure is meV/nm^3 = 1.6 atm (1 atm = 101325 Pa (J/m^3) and
	%  conversion meV = 1.602 176 53*10^-22 J)
%	legend('upper x','upper y','lower x','lower y')
	legend('upper y','lower y','Location','Best')
      end % if reply~=
    end % if mod()
  end % if collision
end % while(true)