Example #1
0
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)
Example #2
0
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)