Beispiel #1
0
    def update(self):
        """Update the simulation by one timestep."""

        stept = self._timing.routine('simulation step')

        stept.start('determining tile movements')

        old = set([t for shape in self._shapes for t in shape.tiles])
        new = dict()

        overlapping = {}
        for t in self._indexedtiles:
            overlapping[t] = []

        for i in range(len(self._shapes)):
            speed = norm(self._shapes[i].v)
            group, v = move(self._indexedtiles,
                            self._shapes[i].tiles,
                            self._shapes[i].v,
                            self._tileadj,
                            self._index)
            self._shapes[i] = Group(list(group.keys()), v)
            for dest, sources in group.items():
                if dest in new:
                    new[dest].append(TileMovement(sources, speed))
                else:
                    new[dest] = [TileMovement(sources, speed)]
                overlapping[dest].append(i)

        stept.start('applying tile movements')

        collisions = {}

        newe = {}

        seen = set()
        for dest, movements in new.items():
            # get all the source tiles contributing to this one
            newe[dest] = NextTileValue(movements)
            if not dest in seen:
                try:
                    old.remove(dest)
                except KeyError:
                    # calculate the amount to build up the leading edge
                    newe[dest].build(self._build * sum([m.speed for m in movements])/len(movements))
                seen.add(dest)

            for pair in combinations(overlapping[dest], 2):
                if pair in collisions:
                    collisions[pair] += 1
                else:
                    collisions[pair] = 1

        # apply the new values
        for t, e in newe.items():
            e.apply(t)

        # clear out abandoned tiles
        for t in old:
            t.emptyocean(self.seafloor())

        # record each continent's total pre-erosion above-sea size
        heights = [sum([t.elevation for t in s.tiles]) for s in self._shapes]

        if self.hasatmosphere:
            stept.start('"simulating" climate')

            seasons = [0.1*v for v in list(range(-10,10,5)) + list(range(10,-10,-5))]
            c = climate(self.tiles, self.adj, seasons, self.cells, self.spin, self.tilt, self.temprange, 0.5, self.haslife, self._climatemappings, self._climateprof)

            if self._climateprof:
                self._climateprof.dump_stats('climate.profile')

            for v, tile in self.tiles.items():
                tile.climate = c[v]['classification']
                tile.seasons = c[v]['seasons']

            stept.start('determining erosion')

            erosion = erode(self.tiles, self.adj)

            for t in self.tiles.values():
                t.erode(erosion, self._erode)

            for t in self.tiles.values():
                # if the tile is in at least one shape, apply the erosion materials
                if len(overlapping[t]) > 0:
                    if len(erosion[t].materials) > 0:
                        t.deposit(sedimentary.deposit(erosion[t].materials, self.haslife, False, t.climate))
                # otherwise, require a certain threshold
                elif sum([m.amount for m in erosion[t].materials]) > 1.5:
                    t.deposit(sedimentary.deposit(erosion[t].materials, self.haslife, True, t.climate))
                    sourceshapes = set()
                    for e in erosion[t].sources:
                        for shape in overlapping[e]:
                            sourceshapes.add(shape)
                    for s in sourceshapes:
                        if not t in self._shapes[s].tiles:
                            self._shapes[s].tiles.append(t)
                    overlapping[t] = list(sourceshapes)
            if self._lifeticks:
                self._lifeticks -= 1
        else:
            self._atmosphereticks -= 1

        stept.start('applying isostatic effects')

        for s, h in zip(self._shapes, heights):
            dh = (h - sum([t.elevation for t in s.tiles]))/float(len(s.tiles))
            for t in s.tiles:
                t.isostasize(dh)

        stept.start('performing random intrusions')

        for t in self.tiles.values():
            if t.subduction > 0:
                if random.random() < 0.1:
                    t.intrude(igneous.intrusive(max(0, min(1, random.gauss(0.85, 0.15)))))
                    t.transform(metamorphic.contact(t.substance[-1], t.intrusion))

        stept.start('applying regional metamorphism')

        for t in self.tiles.values():
            t.transform(metamorphic.regional(t.substance[-1], t.subduction > 0))

        for t in self.tiles.values():
            t.cleartemp()

        stept.start('merging overlapping shapes')

        # merge shapes that overlap a lot
        groups = []
        for pair, count in collisions.items():
            if count > min([len(self._shapes[i].tiles) for i in pair])/10:
                for group in groups:
                    if pair[0] in group:
                        group.add(pair[1])
                        break
                    elif pair[1] in group:
                        group.add(pair[0])
                        break
                else:
                    groups.append(set(pair))

        gone = []
        for group in groups:
            largest = max(group, key=lambda i: len(self._shapes[i].tiles))
            tiles = list(self._shapes[largest].tiles)
            v = array(self._shapes[largest].v) * len(tiles)
            for other in group:
                if other != largest:
                    v += array(self._shapes[other].v) * len(self._shapes[other].tiles)
                    tiles += self._shapes[other].tiles
                    gone.append(self._shapes[other])
            self._shapes[largest].tiles = list(set(tiles))
            v /= len(tiles)
            self._shapes[largest].v = v
        for s in gone:
            self._shapes.remove(s)

        stept.start('randomly splitting shapes')

        # occaisionally split big shapes
        for i in range(len(self._shapes)):
            if random.uniform(0,1) > self._splitnum / len(self._shapes[i].tiles):
                self._shapes[i:i+1] = [Group(ts, self._shapes[i].v + v * self._dp)
                                       for ts, v in split(self._shapes[i].tiles)]

        stept.done()

        self.dirty = True
Beispiel #2
0
 def test_deep_contact_no_granulite(self):
     layers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (25, 26))
     self.assertEqual(layers[-2]['rock']['name'], 'hornfels')
     self.assertEqual(layers[-3]['rock']['type'], 'X')
     self.assertEqual(layers[-4]['rock']['name'], 'hornfels')
Beispiel #3
0
 def test_contact_aureole_depends_on_intrusion_size(self):
     thicklayers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5, 6))
     thinlayers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5.4, 5.6))
     self.assertLess(thinlayers[-2]['thickness'], thicklayers[-2]['thickness'])
Beispiel #4
0
 def test_contact_hornfels_below(self):
     layers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5, 6))
     self.assertEqual(layers[-6]['rock']['name'], 'hornfels')
Beispiel #5
0
 def test_contact_granulite_below(self):
     layers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5, 6))
     self.assertEqual(layers[-5]['rock']['name'], 'granulite')
Beispiel #6
0
 def test_contact_intrusion_left_alone(self):
     layers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5, 6))
     self.assertEqual(layers[-4]['rock']['type'], 'X')
Beispiel #7
0
 def test_contact_leaves_top_alone(self):
     layers = metamorphic.contact([layer({ 'type': 'X' }, 50)], (5, 6))
     self.assertEqual(layers[-1]['rock']['type'], 'X')
Beispiel #8
0
 def test_contact_succeeds(self):
     metamorphic.contact([layer({}, 50)], (5, 6))