class System: def __init__(self, cell=None, nballs=10, step=0, gc=None, input=None, logfile=sys.stdout, velfile=None, velint=0, kT=None, hist=False): self.cell = cell if input is not None: self.load(input) else: self.balls = lattice(nballs, cell) if kT is not None: # ra.seed(1) self.thermalize(kT) self.balls.interact(cell) self.step = step self.gc = gc self.logfile = logfile self.velfile = velfile self.velinterval = velint self.kT = kT self.hist = hist self.histx = Hist(-5, +5, 0.05) self.histy = Hist(-5, +5, 0.05) def thermalize(self, kT): self.balls.randomize(kT) # Remove total translation velsum = np.sum(self.balls.vel, axis=0) velsum /= self.balls.N self.balls.vel -= velsum def OneStep(self, dt): # Progress Momenta (half) self.balls.accel(dt / 2.0) # Progress Position self.balls.forward(dt) self.balls.resetforce() # Force self.pot, virsum = self.balls.interact(self.cell) # Progress Momenta (half) self.balls.accel(dt / 2.0) # temperature scaling # if self.kT is not None: if False: kin = self.balls.kinetic() dof = self.balls.N * self.cell.shape[0] factor = (self.kT * dof / 2.0) / kin factor = 1.0 - (1.0 - factor) * 0.001 self.balls.rescale(factor) # Data output if self.logfile is not None: dof = self.balls.dim * self.balls.N kin = self.balls.kinetic() kT = 2.0 * kin / dof z = 1.0 - virsum / (dof * kT) self.logfile.write( "%s %s %s %s %s %s\n" % (self.step, kT, z, kin + self.pot, kin, self.pot)) if self.velfile is not None and self.step % self.velinterval == 0: for i in range(0, N): self.velfile.write("%s\n" % sqrt(2.0 * self.balls[i].kinetic())) # histogram for v in self.balls.vel: self.histx.accum(v[0], 1.0) if len(v.shape) > 1: self.histy.accum(v[1], 1.0) self.step += 1 def draw(self): if self.gc is not None: dim = self.cell.shape[0] if 2 < dim: avgvel = 1.0 if self.kT is not None: avgvel = sqrt(dim * self.kT) self.balls.draw(self.cell, self.gc, avgvel) else: self.balls.draw(self.cell, self.gc, 0.0) if dim > 1: canvasx = self.cell[0] * self.gc.zoom canvasy = self.cell[1] * self.gc.zoom if self.hist: self.histx.draw(0, canvasy, canvasx, canvasy / 2) self.histx.draw(canvasx, canvasy, canvasx / 2, canvasy, vertical=True) else: canvasx = self.cell[0] * self.gc.zoom canvasy = self.gc.zoom if self.hist: self.histx.draw(0, canvasy, canvasx, canvasy / 2) # self.histx.draw(canvasx,canvasy,canvasx/2,canvasy,vertical=True) def load(self, file): self.balls = [] s = file.readline() self.cell = unserialize(s) s = file.readline() x = unserialize(s) x = int(x[0]) for i in range(0, x): self.balls.append(Particle(file=file)) s = file.readline() # serialize def __str__(self): s = serialize(self.cell) s += "%s\n" % len(self.balls) for i in range(0, len(self.balls)): s += "%s\n" % self.balls[i] return s def save(self, file): file.write("%s\n" % self)
class System: def __init__(self, cell=None, nballs=10, step=0, gc=None, input=None, logfile=sys.stdout, velfile=None, kT=None, hist=False): if hist: self.colorscheme = AbsoluteVelocity(max=5 / 2) self.histx = Hist(-5, +5, 0.05, self.colorscheme) self.histy = Hist(-5, +5, 0.05, self.colorscheme) self.hist = True else: self.colorscheme = None self.hist = False if input is not None: self.load(input) else: self.lattice(cell, nballs) if kT is not None: ra.seed(1) self.thermalize(kT) self.last1 = self.last2 = None # initialize force self.step = step self.gc = gc self.logfile = logfile self.velfile = velfile self.kT = kT self.hist = hist def lattice(self, cell, nballs): self.balls = [] self.cell = cell dim = len(cell) if dim == 1: self.lattice1d(nballs) self.walls = [Wall(coeff=[1.0, 0.0]), Wall(coeff=[1.0, cell[0]])] self.area = 2.0 * 1.0 self.volume = cell[0] elif dim == 2: self.lattice2d(nballs) # d次元の壁はd+1個の係数で指示する。 # 最後の要素以外は単位ベクトルでなければいけない。 self.walls = [ Wall(coeff=[1.0, 0.0, 0.0]), Wall(coeff=[1.0, 0.0, cell[0]]), Wall(coeff=[0.0, 1.0, 0.0]), Wall(coeff=[0.0, 1.0, cell[1]]) ] self.area = 2.0 * (cell[0] + cell[1]) self.volume = cell[0] * cell[1] elif dim == 3: self.lattice3d(nballs) self.walls = [ Wall(coeff=[1.0, 0.0, 0.0, 0.0]), Wall(coeff=[1.0, 0.0, 0.0, cell[0]]), Wall(coeff=[0.0, 1.0, 0.0, 0.0]), Wall(coeff=[0.0, 1.0, 0.0, cell[1]]), Wall(coeff=[0.0, 0.0, 1.0, 0.0]), Wall(coeff=[0.0, 0.0, 1.0, cell[1]]) ] self.area = 2.0 * (cell[0] * cell[1] + cell[1] * cell[2] + cell[0] * cell[2]) self.volume = cell[0] * cell[1] * cell[2] def thermalize(self, kT): dim = len(self.cell) N = len(self.balls) # 1粒子だけにエネルギーを与える。 self.balls[0].randomize(sqrt(dim * kT * float(N))) def rescale(self, factor): for b in self.balls: b.rescale(factor) def lattice1d(self, nballs): n = nballs x = 0.1 while 0 < n: self.balls += [HardDisk([x], [0.0])] n -= 1 x += 1.12 def lattice2d(self, nballs): n = nballs x = 0.1 y = 0.1 while 0 < n: self.balls += [ HardDisk([x, y], [0.0, 0.0], colorscheme=self.colorscheme) ] n -= 1 x += 1.12 if self.cell[0] < x: x -= self.cell[0] - (1.12 / 2.0) y += 1.12 * sqrt(3.0) / 2.0 def lattice3d(self, nballs): n = nballs x = 0.1 y = 0.1 z = 0.1 while 0 < n: self.balls += [HardDisk([x, y, z], [0.0, 0.0, 0.0])] n -= 1 x += 1.12 if self.cell[0] < x: x -= self.cell[0] - (1.12 / 2.0) y += 1.12 * sqrt(3.0) / 2.0 if self.cell[0] < y: y = 0.1 z += 1.12 * sqrt(3.0) / 2.0 def OneCollision(self, deltat): dtmin = deltat object1 = 0 object2 = 0 # 粒子のいずれかが壁にぶつかるまでの最短時間を調べる。 for b in self.balls: for w in self.walls: if b != self.last1 or w != self.last2: dt = b.collideWall(w) if 0 < dt < dtmin: dtmin = dt object1 = b object2 = w # 粒子同士が衝突するまでの最短時間を調べる。 N = len(self.balls) for i in range(0, N): for j in range(i + 1, N): if self.balls[i] != self.last1 or self.balls[j] != self.last2: dt = self.balls[i].collide(self.balls[j]) if 0 < dt < dtmin: dtmin = dt object1 = self.balls[i] object2 = self.balls[j] # 粒子をdtminだけ進める。 for b in self.balls: b.forward(dtmin) impulse = 0.0 # 衝突相手が粒子なら if isinstance(object2, HardDisk): (v1, t1, v2, t2) = object1.reflect(object2) if self.velfile is not None: self.velfile.write("%s %s\n" % (v1, t1)) self.velfile.write("%s %s\n" % (v2, t2)) self.last1 = object1 self.last2 = object2 # 壁に衝突する場合は、壁への力積から圧力が出せる。 elif isinstance(object1, HardDisk): impulse = object1.reflectWall(object2) self.last1 = object1 self.last2 = object2 # 最後に衝突した物体と、消費した時間を返す。 return (dtmin, impulse) def OneStep(self, dt): bunbo = dt * self.area sumpulse = 0.0 ncollision = 0 while 0.0 < dt: # 次の衝突またはdtまで粒子を進める。 (progress, impulse) = self.OneCollision(dt) dt -= progress sumpulse += impulse if impulse == 0.0: ncollision += 1 if self.hist: for b in self.balls: self.histx.accum(b.vel[0], progress) if len(b.vel) > 1: self.histy.accum(b.vel[1], progress) # Data output if self.logfile is not None: dim = len(self.cell) N = len(self.balls) kin = 0.0 for b in self.balls: kin += b.kinetic() kT = 2.0 * kin / (dim * N) #z = 1.0 + virsum / (dim * N * kT ) pressure = sumpulse / bunbo self.logfile.write("%s %s %s %s %s\n" % (self.step, kT, pressure * self.volume / (N * kT), kin, ncollision)) # histogram if self.hist: for b in self.balls: self.histx.accum(b.vel[0], 1.0) if len(b.vel) > 1: self.histy.accum(b.vel[1], 1.0) self.step += 1 def draw(self): if self.gc is not None: dim = len(self.cell) if 2 < dim: avgvel = 0.0 if self.kT > 0.0: avgvel = sqrt(dim * self.kT) tmp = list(self.balls) tmp.sort(key=lambda x: -x.pos[2]) for b in tmp: b.draw(self.cell, self.gc, avgvel) else: for b in self.balls: b.draw(self.cell, self.gc, 0.0) if dim > 1: canvasx = self.cell[0] * self.gc.zoom canvasy = self.cell[1] * self.gc.zoom if self.hist: self.histx.draw(0, canvasy, canvasx, canvasy / 2) self.histx.draw(canvasx, canvasy, canvasx / 2, canvasy, vertical=True) else: canvasx = self.cell[0] * self.gc.zoom canvasy = self.gc.zoom if self.hist: self.histx.draw(0, canvasy, canvasx, canvasy / 2) # self.histx.draw(canvasx,canvasy,canvasx/2,canvasy,vertical=True) def load(self, file): s = file.readline() self.cell = unserialize(s) self.balls = [] s = file.readline() x = unserialize(s) x = int(x[0]) for i in range(0, x): self.balls.append(HardDisk(file=file)) self.walls = [] s = file.readline() x = unserialize(s) x = int(x[0]) for i in range(0, x): self.walls.append(Wall(file=file)) s = file.readline() x = unserialize(s) self.area = float(x[0]) s = file.readline() x = unserialize(s) self.volume = float(x[0]) s = file.readline() # serialize def __str__(self): s = serialize(self.cell) s += "%s\n" % len(self.balls) for i in range(0, len(self.balls)): s += "%s\n" % self.balls[i] s += "%s\n" % len(self.walls) for i in range(0, len(self.walls)): s += "%s\n" % self.walls[i] s += "%s\n" % self.area s += "%s\n" % self.volume return s def save(self, file): file.write("%s\n" % self)