def testOrbit(self):
        Ms = 1.98847 * 10**30  # kg
        # M_earth = 5.9722 * 10**24  # kg
        Mj = 1.899 * 10**27  # kg
        Rj = 778.3 * 10**9  # m
        Tj = 3.743 * 10**8  # s
        # V_earth = 30 * 10**3  # m/s
        # r = 149.6 * 10**9  # m

        vel = 2 * pi * Rj / Tj

        sun_x = np.zeros(3)
        sun_v = np.zeros(3)
        jup_x = np.zeros(3)
        jup_v = np.zeros(3)

        jup_x[0] = Rj
        jup_v[1] = vel
        m = [Ms, Mj]
        v = np.concatenate((sun_x, jup_x, sun_v, jup_v)).reshape(-1)

        sys = NBodySystem(m)
        solver = SystemSolver(sys)
        res = solver.run([0, Tj * 1.5], v)
        solver.plotnd(res)
 def testTwoPoints(self):
     # using IC from TODO
     sys = NBodySystem(body_masses=[1, 1], G=1)
     solver = SystemSolver(sys)
     max_t = 52
     tspan = [0, max_t]
     y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses),
                   dtype=np.float64)
     y0[0:3] = [1, 0, 0]
     y0[3:6] = [-1, 0, 0]
     y0[6:9] = [0, .1, 0]
     y0[9:12] = [0, -.1, 0]
     run = solver.run(tspan, y0)
     # print()
     # print(*y0)
     # print(*run['results'].y[:, -1])
     # clearFigs()
     # fig = solver.plotnd(run)
     # for axes in fig.axes:
     # axes.plot(np.zeros_like(run['results'].y[0]))
     t = run['results'].t
     y = run['results'].y
     # print(t.shape, y.shape)
     # print(t[-1], max_t)
     y0 = y[0]
     y1 = y[3]
     clearFigs()
     plt.figure()
     plt.plot(t, y0)
     plt.plot(t, y1)
    def testFig8Lce(self):  # takes a long time, so its disabled
        sys = NBodySystem(body_masses=[1, 1, 1], G=1)
        solver = SystemSolver(sys)
        tspan = [0, 1.5]
        y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses),
                      dtype=np.float64)

        x1 = np.array([0.97000436, -0.24308753, 0])
        x3p = np.array([-0.93240737, -0.86473146, 0])

        y0[0:3] = x1
        y0[3:6] = -x1
        y0[6:9] = 0
        y0[9:12] = -x3p / 2
        y0[12:15] = -x3p / 2
        y0[15:18] = x3p
        # print(sys.fun(np.zeros_like(y0), y0).reshape(6, -1))
        lce, run = solver.get_lce(tspan[1], y0)
        t = run['results'].t[1:]
        y = run['results'].y[sys.dim:, 1:].reshape(sys.dim, sys.dim, -1)
        #print(y[:, :, -1])
        lces = []
        for i, t_val in enumerate(t):
            Df_y = y[:, :, i]
            lces.append(solver.calc_lce(Df_y, t_val))
        print(lces[-1])
        print(np.mean(lces[-5:]))
        clearFigs()
        plt.figure()
        plt.plot(t, lces)
        plt.show(True)
class TestModel(unittest.TestCase):
    def setUp(self):
        # test data
        self.circle_solver = SystemSolver(CircleSystem())

    def testSomething(self):
        res = self.circle_solver.run([0, 7], [0, 1])['results']
        self.assertTrue(res.success)
        for i, t in enumerate(res.t):
            x, y = res.y[:, i]
            x_exp, y_exp = np.array([-np.sin(t), np.cos(t)])
            self.assertAlmostEqual(x, x_exp, places=2)
            self.assertAlmostEqual(y, y_exp, places=2)

    def testCircleBox(self):
        t_span = [0, 300]
        res = self.circle_solver.run(t_span, [0, 1])
        fig = self.circle_solver.plot2d(res, None)
        ax = fig.get_axes()[0]

        t_dense = np.arange(*t_span, t_span[1]/1000)
        box = np.array([np.cos(t_dense), -np.sin(t_dense)])
        ax.plot(*box, '-')
        newbox = np.sqrt(res['results'].y[0, -1]**2 +
                         res['results'].y[1, -1]**2)*box
        ax.plot(*newbox, '-')
        plt.show(False)
 def testWeirdLenSys(self):
     sys = DoublePendulumSystem(1, 2, .5, 1.5)
     slv = SystemSolver(sys)
     tf = 3
     run1 = slv.run([0, tf], [pi, 1, 1, 0])
     run2 = slv.run([0, tf], [pi, 1.001, 1, 0])
     if self.render:
         self.runRender([run1, run2], 'odd_pend')
 def setUp(self):
     # test data
     self.pendulum_system = DoublePendulumSystem()
     self.pendulum_solver = SystemSolver(self.pendulum_system)
     # run render test
     self.render_til = 10
     self.render_long = False  # slows test a lot
     self.render = False  # slows test
Esempio n. 7
0
 def testLCEPendulumLong(self):
     sys = DoublePendulumSystem()
     slv = SystemSolver(sys)
     theta = pi * 120 / 180
     lce, run = slv.get_lce(T=100, y0=[theta, 0, 0, 0])
     y = run['results'].y
     Df_y0 = y[sys.dim:, -1].reshape(sys.dim, sys.dim)
     print(Df_y0)
     print(lce)
     self.assertGreater(lce, 0)
Esempio n. 8
0
 def testLCEPendulumVaryAngle(self):
     sys = DoublePendulumSystem()
     slv = SystemSolver(sys)
     thetas = []
     lces = []
     for theta in np.arange(0.001, pi + 0.0001, pi / 20):
         lce, _ = slv.get_lce(T=100, y0=[theta, 0, 0, 0])
         thetas.append(theta)
         lces.append(lce)
     clearFigs()
     plt.figure()
     plt.plot(thetas, lces)
     plt.show(True)
    def testFig8(self):
        # using IC from TODO
        sys = NBodySystem(body_masses=[1, 1, 1], G=1)
        solver = SystemSolver(sys)
        tspan = [0, 10]
        y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses),
                      dtype=np.float64)

        x1 = np.array([0.97000436, -0.24308753, 0])
        x3p = np.array([-0.93240737, -0.86473146, 0])

        y0[0:3] = x1
        y0[3:6] = -x1
        y0[6:9] = 0
        y0[9:12] = -x3p / 2
        y0[12:15] = -x3p / 2
        y0[15:18] = x3p
        # print(sys.fun(np.zeros_like(y0), y0).reshape(6, -1))
        run = solver.run(tspan, y0)
        clearFigs()
        solver.plotnd(run)
        # print(run['results'].y[:, -1].reshape(6, -1))
        y_act = run['results'].y[:9]
        run['results'].y = y_act[:3]
        fig = solver.plot3d(run)
        run['results'].y = y_act[3:6]
        fig = solver.plot3d(run, fig=fig)
        run['results'].y = y_act[6:9]
        fig = solver.plot3d(run, fig=fig)
Esempio n. 10
0
    def testRandomInit(self):
        sys = NBodySystem(body_masses=[1, 1, 1], G=1)
        solver = SystemSolver(sys)
        tspan = [0, 100]
        expand = 10
        y0 = np.random.rand(2 * sys.body_dim * len(sys.body_masses)) * expand
        y0[9:] /= expand / 2

        total_mass = np.sum(sys.body_masses)
        vcm = np.zeros(3)
        for m, v in zip(sys.body_masses, y0[9:].reshape(3, -1)):
            vcm += m * v
        vcm /= total_mass
        yps = y0[9:].reshape(3, -1)
        yps -= vcm[None, :]
        run = solver.run(tspan, y0)
        clearFigs()
        solver.plotnd(run)
        # print(run['results'].y[:, -1].reshape(6, -1))
        y_act = run['results'].y[:9]
        run['results'].y = y_act[:3]
        fig = solver.plot3d(run)
        run['results'].y = y_act[3:6]
        fig = solver.plot3d(run, fig=fig)
        run['results'].y = y_act[6:9]
        fig = solver.plot3d(run, fig=fig)
        plt.show(True)
class TestModel(unittest.TestCase):
    def setUp(self):
        # test data
        self.pendulum_system = DoublePendulumSystem()
        self.pendulum_solver = SystemSolver(self.pendulum_system)
        self.run_dp_render = False

    def testDoublePendulum(self):
        clearFigs()
        run = self.pendulum_solver.run([0, 2], [.2, 1, 0, 0])
        run2 = self.pendulum_solver.run([0, 2], [.2, 1.1, 0, 0])
        fig = self.pendulum_solver.plotnd(run)
        self.pendulum_solver.plotnd(run2, fig)
        # plt.show(True)

        clearFigs()
        if self.run_dp_render:
            system = DoublePendulumSystem()
            fig = system.render_path(run, dot_size=2)
            system.render_path(run2, fig=fig, dot_size=2)
            plt.show(True)

    def testDoublePendulumFade(self):
        clearFigs()
        run = self.pendulum_solver.run([0, 5], [.2, 1, 0, 0])
        system = DoublePendulumSystem()
        if self.run_dp_render:
            fig = system.render_fade_trail(run)
            plt.show(False)
            step = .02
            for t in np.arange(.5, 5, step)[1:]:
                plt.pause(.001)
                plt.clf()
                fig = system.render_fade_trail(run, fig=fig, time=t)

    def testDoublePendulumTrail(self):
        clearFigs()
        run = self.pendulum_solver.run([0, 10], [.2, 1, 0, 0])
        system = DoublePendulumSystem()
        if self.run_dp_render:
            fig = system.render_trail(run, time=.5)
            plt.show(False)
            step = .05
            for t in np.arange(.5, 10, step):
                plt.pause(.00001)
                plt.clf()
                fig = system.render_trail(run, fig=fig, time=t)

    def testDoublePendulumTrailFast(self):
        clearFigs()
        run = self.pendulum_solver.run([0, 10], [.2, 1, 0, 3])
        system = DoublePendulumSystem()
        if self.run_dp_render:
            fig = system.render_trail(run, time=.5)
            plt.show(False)
            step = .05
            for t in np.arange(.5, 10, step):
                plt.pause(.00001)
                plt.clf()
                fig = system.render_trail(run, fig=fig, time=t)
 def testLCE(self):
     # slv.calc_lce(Df_y0, T)
     sys = RestrictedCircular3Body()
     slv = SystemSolver(sys)
     lce, lce_run = slv.get_lce(T=100)
     t = lce_run['results'].t
     y = lce_run['results'].y
     sys_dim = sys.dim
     lces = []
     start_t = 10
     for i in range(start_t, t.shape[0]):
         Df_y0 = y[sys_dim:, i].reshape(sys_dim, sys_dim)
         lce = slv.calc_lce(Df_y0, t[i])
         lces.append(lce)
     plt.plot(t[start_t:], lces)
     plt.show(True)
Esempio n. 13
0
 def runLCETest(self, sigma, rho, beta, l1):
     sys = LorenzSystem(sigma, rho, beta)
     slv = SystemSolver(sys)
     lce, run = slv.get_lce(T=100)
     T0 = 0
     t = run['results'].t[T0:]
     y = run['results'].y[:, T0:]
     lces = []
     for i, t_val in enumerate(t):
         Df_y0 = y[sys.dim:, i].reshape(sys.dim, sys.dim)
         lces.append(slv.calc_lce(Df_y0, t_val))
     clearFigs()
     plt.figure()
     plt.plot(t, lces)
     plt.show(True)
     print(Df_y0)
     print(lce, l1, (lce - l1) / l1)
     self.assertAlmostEqual((lce - l1) / l1, 0, places=0)
Esempio n. 14
0
    def testFig8LcePartition(self):  # takes a long time, so its disabled
        sys = NBodySystem(body_masses=[1, 1, 1], G=1)
        solver = SystemSolver(sys)
        tspan = [0, 10]
        y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses),
                      dtype=np.float64)

        x1 = np.array([0.97000436, -0.24308753, 0])
        x3p = np.array([-0.93240737, -0.86473146, 0])

        y0[0:3] = x1
        y0[3:6] = -x1
        y0[6:9] = 0
        y0[9:12] = -x3p / 2
        y0[12:15] = -x3p / 2
        y0[15:18] = x3p
        # print(sys.fun(np.zeros_like(y0), y0).reshape(6, -1))
        tspan, lces = solver.quick_lce(tspan[1], y0, partition=None)
        print(np.mean(lces[-5:]))
        clearFigs()
        plt.figure()
        plt.plot(tspan, lces)
        plt.show(True)
 def testExample(self):
     sys = RestrictedCircular3Body()
     slv = SystemSolver(sys)
     lce, lce_run = slv.get_lce()
     slv.calc_lce
     # print(lce)
     init = [1, -1, 1, -1]
     run = slv.run([0, 5], init)
     run['results'].y = run['results'].y[:2, :]
     slv.plot2d(run)
Esempio n. 16
0
class TestModel(unittest.TestCase):
    def setUp(self):
        # test data
        self.circle_solver = SystemSolver(CircleSystem())
        self.lorenz_solver = SystemSolver(LorenzSystem())

    def test3dGraph(self):
        res = self.lorenz_solver.run([0, 10], [1, 1, 1])
        fig = self.lorenz_solver.plotnd(res)
        self.lorenz_solver.plot3d(res)
        self.assertEqual(4, len(fig.get_axes()))

    def test2dGraph(self):
        res = self.circle_solver.run([0, 10], [1, 1])
        fig = self.circle_solver.plotnd(res)
        self.circle_solver.plot2d(res)
        self.assertEqual(3, len(fig.get_axes()))

    def testMultiGraph(self):
        run1 = self.lorenz_solver.run([0, 20], [1, 1, 1])
        run2 = self.lorenz_solver.run([0, 20], [1, 1, 1])
        run3 = self.lorenz_solver.run([0, 20], [1, 1, 1 + 10**-9])
        fig = self.lorenz_solver.plot3d(run1)
        fig = self.lorenz_solver.plot3d(run2, fig)
        self.lorenz_solver.plot3d(run3, fig)
        # You should see that orange (2nd graph) covers blue (1st graph) while
        # adding a billionth to green (3rd graph) causes it to diverge.

    def testMulti2dGraph(self):
        run1 = self.circle_solver.run([0, 20], [0, 2])
        run2 = self.circle_solver.run([0, 20], [0, 1])
        fig = self.circle_solver.plot2d(run1)
        self.circle_solver.plot2d(run2, fig)

    def testMultiNdGraph(self):
        run1 = self.lorenz_solver.run([0, 20], [1, 1, 1])
        run2 = self.lorenz_solver.run([0, 20], [1, 1, 1.001])
        fig = self.lorenz_solver.plotnd(run1)
        self.lorenz_solver.plotnd(run2, fig)
Esempio n. 17
0
from echonn.sys import LorenzSystem, SystemSolver

if __name__ == "__main__":
    data = [
        [16, 45.92, 4, 1.50255],
        [16, 40, 4, 1.37446],
        [10, 28, 8 / 3, 0.90566],
    ]
    results = []
    for sigma, rho, beta, lambda_ in data:

        lces = []
        print('calculating lces...')
        for i in range(10):
            sys = LorenzSystem(sigma, rho, beta)
            slv = SystemSolver(sys)

            lce, _ = slv.get_lce()
            print('\t{}:'.format(i), lce)
            lces.append(lce)
        res = {}
        res['beta'] = beta
        res['rho'] = rho
        res['sigma'] = sigma
        res['lambda'] = lambda_
        res['mean'] = np.mean(lces)
        res['std'] = np.std(lces)
        res['error'] = res['mean'] - lambda_
        res['relative error'] = res['error'] / lambda_
        print(res)
        print()
Esempio n. 18
0
import os
from echonn.sys import NBodySystem, SystemSolver
import numpy as np
import matplotlib.pyplot as plt

dir_pre = os.path.join('..', 'images', '3body')
sys = NBodySystem(body_masses=[1, 1, 1], body_dim=2, G=1)
solver = SystemSolver(sys)
tspan = [0, 200]
y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses), dtype=np.float64)

x1 = np.array([0.97000436, -0.24308753])
x3p = np.array([-0.93240737, -0.86473146])

y0[0:2] = x1
y0[2:4] = -x1
# y0[4:6] = zero
y0[6:8] = -x3p / 2
y0[8:10] = -x3p / 2
y0[10:12] = x3p

# print(sys.fun(np.zeros_like(y0), y0).reshape(6, -1))
lce, run = solver.get_lce(tspan[1], y0)
t = run['results'].t[1:]
y = run['results'].y[sys.dim:, 1:].reshape(sys.dim, sys.dim, -1)
#print(y[:, :, -1])
lces = []
for i, t_val in enumerate(t):
    Df_y = y[:, :, i]
    lces.append(solver.calc_lce(Df_y, t_val))
Esempio n. 19
0
import numpy as np
import os
from echonn.sys import DoublePendulumSystem, SystemSolver
import matplotlib.pyplot as plt
from scipy.constants import pi

if __name__ == "__main__":
    sys = DoublePendulumSystem()
    slv = SystemSolver(sys)
    thetas = np.arange(0.001, pi + 0.0001, pi / 20)
    out_img = os.path.join('..', 'images', 'chaos_vs_energy_in_doub_pend.png')
    lces = []
    for theta in thetas:
        lce, _ = slv.get_lce(T=200, y0=[theta, 0, 0, 0])
        lces.append(lce)
    plt.title('Largest LCE vs Inner Theta IC')
    plt.xlabel('Inner Theta')
    plt.ylabel('Largest LCE')
    plt.plot(180 * thetas / pi, lces)
    try:
        if os.path.exists(out_img):
            os.remove(out_img)
    except:
        pass  # don't worry about it
    plt.savefig(out_img)
    plt.show(True)
Esempio n. 20
0
import os
import pickle
import numpy as np
import matplotlib.pyplot as plt
from copy import deepcopy

from echonn.sys import SystemSolver

res = pickle.load(open('lorenz_results.p', 'rb'))
run, lce, ts_data, results = res
sys = run['system']
slvr = SystemSolver(sys)
dir_pre = os.path.join('..', 'images', 'lorenz')

print('lce:', lce[0])

# LCE
lce_val, lce_run = lce
T0 = 0
t = lce_run['results'].t[T0:]
y = lce_run['results'].y[:, T0:]
lces = []
for i, t_val in enumerate(t):
    Df_y0 = y[sys.dim:, i].reshape(sys.dim, sys.dim)
    lces.append(slvr.calc_lce(Df_y0, t_val))
plt.figure()
plt.title(f'Lorenz LCE ({lce_val:.3}) vs t')
plt.xlabel('t')
plt.ylabel('LCE')
plt.plot(t, lces)
plt.savefig(os.path.join(dir_pre, 'lce_converge.png'))
import os
import pickle
import numpy as np
import matplotlib.pyplot as plt
from copy import deepcopy

from echonn.sys import SystemSolver

res = pickle.load(open('doub_pend_results.p', 'rb'))
run, lce, ts_data, results = res
sys = run['system']
slvr = SystemSolver(sys)
dir_pre = os.path.join('..', 'images', 'doub_pend')

# print small details
print('lce:', lce[0])
# LCE
lce_val, lce_run = lce
T0 = 0
t = lce_run['results'].t[T0:]
y = lce_run['results'].y[:, T0:]
lces = []
for i, t_val in enumerate(t):
    Df_y0 = y[sys.dim:, i].reshape(sys.dim, sys.dim)
    lces.append(slvr.calc_lce(Df_y0, t_val))
plt.figure()
plt.title(f'Double Pendulum LCE ({lce_val:.3}) vs t')
plt.xlabel('t')
plt.ylabel('LCE')
plt.plot(t, lces)
plt.savefig(os.path.join(dir_pre, 'lce_converge.png'))
 def setUp(self):
     # test data
     self.pendulum_system = DoublePendulumSystem()
     self.pendulum_solver = SystemSolver(self.pendulum_system)
     self.run_dp_render = False
Esempio n. 23
0
 def setUp(self):
     # test data
     self.circle_solver = SystemSolver(CircleSystem())
Esempio n. 24
0
import numpy as np
import matplotlib.pyplot as plt
from echonn.sys import SystemSolver, RestrictedCircular3Body, LyapunovSystem

if __name__ == "__main__":
    mu = 0.5
    sys = RestrictedCircular3Body(body_ratio=mu)
    lce = LyapunovSystem(sys)

    #init = [1, -1, .1, .1]
    init = np.array(1000 * np.random.rand(4), dtype=int) / 1000
    slv = SystemSolver(sys)
    #run = slv.run([0, 10], init, max_step=0.001)
    T = 100
    lce, run = slv.get_lce(T=T, y0=init)
    #lce, run = slv.get_lce(T=T)
    mat = run['results'].y[4:, -1].reshape(4, 4)
    run['results'].y = run['results'].y[[0, 2], :]
    slv.plot2d(run)
    plt.scatter([-sys.alpha, sys.mu], [0, 0])
    print(init)
    print(mat)
    print('lce:', lce)
    #plt.xlim((-15, 15))
    #plt.ylim((-15, 15))
    # Saved manually since it can't be scripted
    plt.show(True)
Esempio n. 25
0
import os
from echonn.sys import NBodySystem, SystemSolver
import numpy as np
import matplotlib.pyplot as plt

dir_pre = os.path.join('..', 'images', '3body')
sys = NBodySystem(body_masses=[1, 1, 1], G=1)
solver = SystemSolver(sys)

y0 = np.zeros(2 * sys.body_dim * len(sys.body_masses), dtype=np.float64)

x1 = np.array([0.97000436, -0.24308753, 0])
x3p = np.array([-0.93240737, -0.86473146, 0])

y0[0:3] = x1
y0[3:6] = -x1
y0[6:9] = 0
y0[9:12] = -x3p / 2
y0[12:15] = -x3p / 2
y0[15:18] = x3p

tspan = [0, 100]
# print(sys.fun(np.zeros_like(y0), y0).reshape(6, -1))
run = solver.run(tspan, y0)
# solver.plotnd(run)
# print(run['results'].y[:, -1].reshape(6, -1))
y_act = run['results'].y[:9]
run['results'].y = y_act[:3]
fig = solver.plot3d(run)
run['results'].y = y_act[3:6]
fig = solver.plot3d(run, fig=fig)
Esempio n. 26
0
 def setUp(self):
     # test data
     self.circle_solver = SystemSolver(CircleSystem())
     self.lorenz_solver = SystemSolver(LorenzSystem())
Esempio n. 27
0
            self.k[i] *= self.e[i-1] * self.k[i-1]
        self.levels = levels

    def fun(self, t, v):
        r = self.r
        k = self.k
        e = self.e

        trans = r * v*v/k
        y = np.zeros_like(v)
        y[0] += r * v[0]
        y[1:] += e*trans[:-1]
        y -= trans
        return y

if __name__ == '__main__':
    biome1 = {'rate': 1, 'capacity': 1000, 'efficiency': [.1, .12], 'levels':3}
    biome2 = {'rate': .1, 'capacity': 100, 'efficiency': [.1, .9], 'levels':3}
    biome3 = {'rate': .01, 'capacity': 5000, 'efficiency': [.1, .2], 'levels':3}
    problem = EcoSystem([biome1, biome2, biome3])
    solver = SystemSolver(problem)
    y0 = np.zeros(problem.dim)
    y0[0] = 1
    y0[3] = 1
    y0[4] = 1000
    y0[6] = 1
    solver.run([0, 200], y0)
    solver.plotnd()
    plt.show(True)

Esempio n. 28
0
import os
import numpy as np
import matplotlib.pyplot as plt
from echonn.sys import LorenzSystem, SystemSolver

if __name__ == "__main__":
    lorenz_3d_plot = os.path.join('..', 'images', 'lorenz_3d_plot.png')
    lorenz_nd_plot = os.path.join('..', 'images', 'lorenz_nd_plot.png')
    slv = SystemSolver(LorenzSystem())
    res = slv.run([0, 50], [10, 20, 30])
    slv.plotnd(res, dims=['x', 'y', 'z'])
    plt.savefig(lorenz_nd_plot)
    slv.plot3d(res)
    plt.savefig(lorenz_3d_plot)
    plt.show(True)
Esempio n. 29
0
from echonn.sys import CircleSystem, SystemSolver

if __name__ == "__main__":
    sys = SystemSolver(CircleSystem())
    lce, run = sys.get_lce()
    print('lce:', lce)
    print(run['results'].y[2:, -1].reshape(2, 2))
Esempio n. 30
0
 def testCircleLCE(self):
     sys = SystemSolver(CircleSystem())
     lce, run = sys.get_lce()
     self.assertAlmostEqual(lce, 0, places=4)