Пример #1
0
 def test_get_with_default_value(self):
     ptree = PropertyTree()
     # double
     self.assertEqual(
         ptree.get_double_with_default_value('missing_double', 3.14), 3.14)
     ptree.put_double('present_double', 1.41)
     self.assertEqual(
         ptree.get_double_with_default_value('present_double', 3.14), 1.41)
     # string
     self.assertEqual(
         ptree.get_string_with_default_value('missing_string', 'missing'),
         'missing')
     ptree.put_string('present_string', 'present')
     self.assertEqual(
         ptree.get_string_with_default_value('present_string', 'missing'),
         'present')
     # int
     self.assertEqual(ptree.get_int_with_default_value('missing_int', 255),
                      255)
     ptree.put_int('present_int', 0)
     self.assertEqual(ptree.get_int_with_default_value('present_int', 255),
                      0)
     # bool
     self.assertEqual(
         ptree.get_bool_with_default_value('missing_bool', True), True)
     ptree.put_bool('present_bool', False)
     self.assertEqual(
         ptree.get_bool_with_default_value('present_bool', True), False)
Пример #2
0
 def test_property_tree(self):
     # ptree as container to store int, double, string, and bool
     ptree = PropertyTree()
     ptree.put_int('dim', 3)
     self.assertEqual(ptree.get_int('dim'), 3)
     ptree.put_double('path.to.pi', 3.14)
     self.assertEqual(ptree.get_double('path.to.pi'), 3.14)
     ptree.put_string('good.news', 'it works')
     self.assertEqual(ptree.get_string('good.news'), 'it works')
     ptree.put_bool('is.that.a.good.idea', False)
     self.assertEqual(ptree.get_bool('is.that.a.good.idea'), False)
    def test_consistency_pycap_simulation(self):
        #
        # weak run test; simply ensures that Dualfoil object
        # can be run with pycap.Charge
        #
        df1 = Dualfoil(path=path)  # will use pycap
        df2 = Dualfoil(path=path)  # manual runs
        im = df_manip.InputManager(path=path)

        # testing a charge-to-hold-const-voltage
        # manual
        # use InputManager to set the input file
        c = -12.0  # constant current
        im.add_new_leg(c, 5.0, 1)
        df1.run()
        df1.outbot.update_output()
        v = 4.54  # constant voltage
        im.add_new_leg(v, 5.0, 0)
        df1.run()
        df1.outbot.update_output()

        # pycap simulation
        # build a ptree input
        ptree = PropertyTree()
        ptree.put_double('time_step', 300.0)  # 5 minutes
        ptree.put_string('charge_mode', 'constant_current')
        ptree.put_double('charge_current', 12.0)
        ptree.put_string('charge_stop_at_1', 'voltage_greater_than')
        ptree.put_double('charge_voltage_limit', 4.54)
        ptree.put_bool('charge_voltage_finish', True)
        # hold end voltage after either 5 minutes have passed
        # OR current falls under 1 ampere
        ptree.put_double('charge_voltage_finish_max_time', 300.0)
        ptree.put_double('charge_voltage_finish_current_limit', 1.0)

        const_current_const_voltage = Charge(ptree)
        const_current_const_voltage.run(df2)

        # check the output lists of both devices
        o1 = df1.outbot.output
        o2 = df2.outbot.output
        self.assertEqual(len(o1['time']), len(o2['time']))
        for i in range(len(o1['time'])):
            self.assertAlmostEqual(o1['time'][i], o2['time'][i])
            # BELOW: relaxed delta for voltage
            # REASON: dualfoil cuts off its voltages at 5
            #   decimal places, meaning that this end-digit
            #   is subject to roundoff errors
            error = 1e-5
            self.assertAlmostEqual(o1['voltage'][i],
                                   o2['voltage'][i],
                                   delta=error)
            self.assertAlmostEqual(o1['current'][i], o2['current'][i])
    def test_consistency_pycap_simulation(self):
        # 
        # weak run test; simply ensures that Dualfoil object
        # can be run with pycap.Charge
        #
        df1 = Dualfoil(path=path)  # will use pycap
        df2 = Dualfoil(path=path)  # manual runs
        im = df_manip.InputManager(path=path)

        # testing a charge-to-hold-const-voltage
        # manual 
        # use InputManager to set the input file
        c = -12.0  # constant current
        im.add_new_leg(c, 5.0, 1)
        df1.run()
        df1.outbot.update_output()
        v = 4.54  # constant voltage
        im.add_new_leg(v, 5.0, 0)
        df1.run()
        df1.outbot.update_output()
        
        # pycap simulation
        # build a ptree input
        ptree = PropertyTree()
        ptree.put_double('time_step', 300.0)  # 5 minutes
        ptree.put_string('charge_mode', 'constant_current')
        ptree.put_double('charge_current', 12.0)
        ptree.put_string('charge_stop_at_1', 'voltage_greater_than')
        ptree.put_double('charge_voltage_limit', 4.54)
        ptree.put_bool('charge_voltage_finish', True)
        # hold end voltage after either 5 minutes have passed
        # OR current falls under 1 ampere
        ptree.put_double('charge_voltage_finish_max_time', 300.0)
        ptree.put_double('charge_voltage_finish_current_limit', 1.0)

        const_current_const_voltage = Charge(ptree)
        const_current_const_voltage.run(df2)

        # check the output lists of both devices
        o1 = df1.outbot.output
        o2 = df2.outbot.output
        self.assertEqual(len(o1['time']), len(o2['time']))
        for i in range(len(o1['time'])):
            self.assertAlmostEqual(o1['time'][i], o2['time'][i])
            # BELOW: relaxed delta for voltage
            # REASON: dualfoil cuts off its voltages at 5
            #   decimal places, meaning that this end-digit
            #   is subject to roundoff errors
            error = 1e-5
            self.assertAlmostEqual(o1['voltage'][i], o2['voltage'][i],
                                   delta=error)
            self.assertAlmostEqual(o1['current'][i], o2['current'][i])
Пример #5
0
def run_discharge(device, ptree):
    data = initialize_data()

    # (re)charge the device
    initial_voltage = ptree.get_double('initial_voltage')

    charge_database = PropertyTree()
    charge_database.put_string('charge_mode', 'constant_current')
    charge_database.put_double('charge_current', 10.0)
    charge_database.put_string('charge_stop_at_1', 'voltage_greater_than')
    charge_database.put_double('charge_voltage_limit', initial_voltage)
    charge_database.put_bool('charge_voltage_finish', True)
    charge_database.put_double('charge_voltage_finish_current_limit', 1e-2)
    charge_database.put_double('charge_voltage_finish_max_time', 600)
    charge_database.put_double('charge_rest_time', 0)
    charge_database.put_double('time_step', 10.0)

    charge = Charge(charge_database)
    start = time()
    charge.run(device, data)
    end = time()
    # used for tracking time of this substep
    print('Charge: %s min' % ((end-start) / 60))

    data['time'] -= data['time'][-1]

    # discharge at constant power
    discharge_power = ptree.get_double('discharge_power')
    final_voltage = ptree.get_double('final_voltage')
    time_step = ptree.get_double('time_step')

    discharge_database = PropertyTree()
    discharge_database.put_string('discharge_mode', 'constant_power')
    discharge_database.put_double('discharge_power', discharge_power)
    discharge_database.put_string('discharge_stop_at_1', 'voltage_less_than')
    discharge_database.put_double('discharge_voltage_limit', final_voltage)
    discharge_database.put_double('discharge_rest_time', 10 * time_step)
    discharge_database.put_double('time_step', time_step)

    discharge = Discharge(discharge_database)
    start = time()
    discharge.run(device, data)
    end = time()
    # used for tracking time of this substep
    print('Discharge: %s min' % ((end-start) / 60))

    return data
Пример #6
0
def run_discharge(device, ptree):
    data = initialize_data()

    # (re)charge the device
    initial_voltage = ptree.get_double('initial_voltage')

    charge_database = PropertyTree()
    charge_database.put_string('charge_mode', 'constant_current')
    charge_database.put_double('charge_current', 10.0)
    charge_database.put_string('charge_stop_at_1', 'voltage_greater_than')
    charge_database.put_double('charge_voltage_limit', initial_voltage)
    charge_database.put_bool('charge_voltage_finish', True)
    charge_database.put_double('charge_voltage_finish_current_limit', 1e-2)
    charge_database.put_double('charge_voltage_finish_max_time', 600)
    charge_database.put_double('charge_rest_time', 0)
    charge_database.put_double('time_step', 10.0)

    charge = Charge(charge_database)
    start = time()
    charge.run(device, data)
    end = time()
    # used for tracking time of this substep
    print('Charge: %s min' % ((end - start) / 60))

    data['time'] -= data['time'][-1]

    # discharge at constant power
    discharge_power = ptree.get_double('discharge_power')
    final_voltage = ptree.get_double('final_voltage')
    time_step = ptree.get_double('time_step')

    discharge_database = PropertyTree()
    discharge_database.put_string('discharge_mode', 'constant_power')
    discharge_database.put_double('discharge_power', discharge_power)
    discharge_database.put_string('discharge_stop_at_1', 'voltage_less_than')
    discharge_database.put_double('discharge_voltage_limit', final_voltage)
    discharge_database.put_double('discharge_rest_time', 10 * time_step)
    discharge_database.put_double('time_step', time_step)

    discharge = Discharge(discharge_database)
    start = time()
    discharge.run(device, data)
    end = time()
    # used for tracking time of this substep
    print('Discharge: %s min' % ((end - start) / 60))

    return data
    def test_accuracy_pycap_simulation(self):
        #
        # tests the accuracy of a pycap simulation against a
        # straight run dualfoil sim with different timesteps
        #
        df1 = Dualfoil(path=path)  # manual runs
        df2 = Dualfoil(path=path)  # pycap simulation
        im = df_manip.InputManager(path=path)

        # testing a charge-to-hold-const-voltage
        # manual
        # use InputManager to set the input file
        c = -10.0  # constant charge current
        # charge for 5 minutes straight
        im.add_new_leg(c, 5, 1)
        df1.run()
        df1.outbot.update_output()
        v = 4.539  # expected voltage after 5 minutes
        # hold constant voltage for 3 minutes straight
        im.add_new_leg(v, 3.0, 0)
        df1.run()
        df1.outbot.update_output()

        # pycap simulation
        # build a ptree input
        ptree = PropertyTree()
        ptree.put_double('time_step', 30.0)  # 30 second time step
        ptree.put_string('charge_mode', 'constant_current')
        ptree.put_double('charge_current', 10.0)
        ptree.put_string('charge_stop_at_1', 'voltage_greater_than')
        ptree.put_double('charge_voltage_limit', v)
        ptree.put_bool('charge_voltage_finish', True)
        # hold end voltage after either 3 minutes have passed
        # OR current falls under 1 ampere
        ptree.put_double('charge_voltage_finish_max_time', 180.0)
        ptree.put_double('charge_voltage_finish_current_limit', 1.0)

        const_current_const_voltage = Charge(ptree)
        const_current_const_voltage.run(df2)

        o1 = df1.outbot.output  # contains sim1 output
        o2 = df2.outbot.output  # contains sim2 output

        # affirm we make it this far and have usable data
        self.assertTrue(len(o1['time']) > 0)
        self.assertTrue(len(o2['time']) > 0)
        # lengths of data should be different
        self.assertFalse(len(o1['time']) == len(o2['time']))

        # TEST LOGIC:
        #  -Merge the two outputs into one, sorted by
        #   increasing time stamps.
        #  -Compare the consistency of the two simulations
        #   by checking for smooth changes within the curves
        #   of the combined output lists
        o1['time'].extend(o2['time'])
        time = ar(o1['time'])  # nparray
        o1['voltage'].extend(o2['voltage'])
        voltage = ar(o1['voltage'])  # nparray
        o1['current'].extend(o2['current'])
        current = ar(o1['current'])  # np array
        # create a dictionary with the combined output lists
        output = {'time': time, 'voltage': voltage, 'current': current}
        # sort based on time, keeping the three types aligned
        key = argsort(output['time'])
        # for using the key to sort the list
        tmp = {'time': [], 'voltage': [], 'current': []}
        for i in key:
            tmp['time'].append(output['time'][i])
            tmp['voltage'].append(output['voltage'][i])
            tmp['current'].append(output['current'][i])
        # reassign ordered set to `output` as nparrays
        output['time'] = ar(tmp['time'])
        output['voltage'] = ar(tmp['voltage'])
        output['current'] = ar(tmp['current'])

        # BELOW: first 20 seconds are identical time stamps;
        #     skip these to avoid errors from incorrect sorting
        # REASON FOR ERROR: Dualfoil only prints time data as
        #     precice as minutes to three decimal places. So when
        #     the following is generated....
        #       Manual Run         |       Pycap Simulation
        #  (min)     (V)     (amp) |  (min)     (V)     (amp)
        #  .001   4.52345    10.0  |  .001   4.52345    10.0
        #  .001   4.52349    10.0  |  .001   4.52349    10.0
        #           ...                       ...
        #     ...python's `sorted()` function has no way of
        #     distinguishing entries; it instead returns this:
        # [
        #   (.001, 4.52345, 10.0),
        #   (.001, 4.52349, 10.0),  <- these two should
        #   (.001, 4.52345, 10.0),  <-   be switched
        #   (.001, 4.52349, 10.0)
        # ]
        # SOLUTION: consistency test affirms that the exact same
        #     time step will produce same current and voltage, so
        #     skip ahead to first instance where time stamps will
        #     be out of alignment
        i = 0
        while output['time'][i] <= 0.4:  # 24 seconds
            i = i + 1
        index_limit = len(output['time']) - 1

        # go through and affirm smoothness of curve
        while i < index_limit:
            # Check if time values are the same to 3 decimal places.
            # If so, current and voltage are not guarunteed
            #   to also be exactly the same, but should be close
            if output['time'][i] == output['time'][i - 1]:
                # affirm that current is virtually the same
                self.assertAlmostEqual(output['current'][i],
                                       output['current'][i - 1])
                # BELOW: delta is eased slightly
                # REASON: `sorted()` can't tell which entry came
                #   first from same time-stamp if from different
                #   simulations; allow for this with error
                error = 3e-5
                self.assertAlmostEqual(output['voltage'][i],
                                       output['voltage'][i - 1],
                                       delta=error)
            else:
                # Time values are different
                # Check to affirm that the variable NOT being held
                # constant is steadily increasing / decreasing

                # First part happens in first 4 minutes
                if output['time'][i] <= 5.0:  # part 1, const currrent
                    # current should be equal
                    self.assertEqual(output['current'][i],
                                     output['current'][i - 1])
                    # voltage should not have decreased
                    self.assertTrue(output['voltage'][i],
                                    output['voltage'][i - 1])
                else:  # part 2, const voltage
                    # current should be getting less positive
                    self.assertTrue(
                        output['current'][i] <= output['current'][i - 1],
                        msg=(output['current'][i - 2:i + 10],
                             output['time'][i - 2:i + 10]))
                    # voltage should decrease, then stay at 4.54
                    if output['voltage'][i - 1] == 4.54:
                        self.assertEqual(output['voltage'][i],
                                         output['voltage'][i - 1])
                    else:
                        self.assertTrue(
                            output['voltage'][i] <= output['voltage'][i - 1])
            # update index
            i = i + 1
    def test_accuracy_pycap_simulation(self):
        #
        # tests the accuracy of a pycap simulation against a 
        # straight run dualfoil sim with different timesteps
        #
        df1 = Dualfoil(path=path)  # manual runs
        df2 = Dualfoil(path=path)  # pycap simulation
        im = df_manip.InputManager(path=path)

        # testing a charge-to-hold-const-voltage
        # manual 
        # use InputManager to set the input file
        c = -10.0  # constant charge current
        # charge for 5 minutes straight
        im.add_new_leg(c, 5, 1)
        df1.run()
        df1.outbot.update_output()
        v = 4.539  # expected voltage after 5 minutes
        # hold constant voltage for 3 minutes straight
        im.add_new_leg(v, 3.0, 0)
        df1.run()
        df1.outbot.update_output()

        # pycap simulation
        # build a ptree input
        ptree = PropertyTree()
        ptree.put_double('time_step', 30.0)  # 30 second time step
        ptree.put_string('charge_mode', 'constant_current')
        ptree.put_double('charge_current', 10.0)
        ptree.put_string('charge_stop_at_1', 'voltage_greater_than')
        ptree.put_double('charge_voltage_limit', v)
        ptree.put_bool('charge_voltage_finish', True)
        # hold end voltage after either 3 minutes have passed
        # OR current falls under 1 ampere
        ptree.put_double('charge_voltage_finish_max_time', 180.0)
        ptree.put_double('charge_voltage_finish_current_limit', 1.0)

        const_current_const_voltage = Charge(ptree)
        const_current_const_voltage.run(df2)

        o1 = df1.outbot.output     # contains sim1 output
        o2 = df2.outbot.output     # contains sim2 output

        # affirm we make it this far and have usable data
        self.assertTrue(len(o1['time']) > 0)
        self.assertTrue(len(o2['time']) > 0)
        # lengths of data should be different
        self.assertFalse(len(o1['time']) == len(o2['time']))

        # TEST LOGIC:
        #  -Merge the two outputs into one, sorted by
        #   increasing time stamps.
        #  -Compare the consistency of the two simulations
        #   by checking for smooth changes within the curves
        #   of the combined output lists
        o1['time'].extend(o2['time'])
        time = ar(o1['time'])  # nparray
        o1['voltage'].extend(o2['voltage'])
        voltage = ar(o1['voltage'])  # nparray
        o1['current'].extend(o2['current'])
        current = ar(o1['current'])  # np array
        # create a dictionary with the combined output lists
        output = {'time': time,
                  'voltage': voltage,
                  'current': current
                 }
        # sort based on time, keeping the three types aligned
        key = argsort(output['time'])
        # for using the key to sort the list
        tmp = {'time': [], 'voltage': [], 'current': []}
        for i in key:
            tmp['time'].append(output['time'][i])
            tmp['voltage'].append(output['voltage'][i])
            tmp['current'].append(output['current'][i])
        # reassign ordered set to `output` as nparrays
        output['time'] = ar(tmp['time'])
        output['voltage'] = ar(tmp['voltage'])
        output['current'] = ar(tmp['current'])

        # BELOW: first 20 seconds are identical time stamps;
        #     skip these to avoid errors from incorrect sorting
        # REASON FOR ERROR: Dualfoil only prints time data as 
        #     precice as minutes to three decimal places. So when
        #     the following is generated....
        #       Manual Run         |       Pycap Simulation
        #  (min)     (V)     (amp) |  (min)     (V)     (amp)
        #  .001   4.52345    10.0  |  .001   4.52345    10.0
        #  .001   4.52349    10.0  |  .001   4.52349    10.0
        #           ...                       ...
        #     ...python's `sorted()` function has no way of 
        #     distinguishing entries; it instead returns this:
        # [ 
        #   (.001, 4.52345, 10.0),
        #   (.001, 4.52349, 10.0),  <- these two should
        #   (.001, 4.52345, 10.0),  <-   be switched
        #   (.001, 4.52349, 10.0)
        # ] 
        # SOLUTION: consistency test affirms that the exact same
        #     time step will produce same current and voltage, so
        #     skip ahead to first instance where time stamps will 
        #     be out of alignment
        i = 0
        while output['time'][i] <= 0.4:  # 24 seconds
            i = i + 1
        index_limit = len(output['time'])-1  
        
        # go through and affirm smoothness of curve
        while i < index_limit:
            # Check if time values are the same to 3 decimal places.
            # If so, current and voltage are not guarunteed 
            #   to also be exactly the same, but should be close
            if output['time'][i] == output['time'][i-1]:
                # affirm that current is virtually the same
                self.assertAlmostEqual(output['current'][i],
                                       output['current'][i-1])
                # BELOW: delta is eased slightly
                # REASON: `sorted()` can't tell which entry came
                #   first from same time-stamp if from different
                #   simulations; allow for this with error
                error = 3e-5
                self.assertAlmostEqual(output['voltage'][i],
                                       output['voltage'][i-1],
                                       delta=error)
            else:  
                # Time values are different
                # Check to affirm that the variable NOT being held 
                # constant is steadily increasing / decreasing

                # First part happens in first 4 minutes
                if output['time'][i] <= 5.0:  # part 1, const currrent
                    # current should be equal
                    self.assertEqual(output['current'][i],
                                     output['current'][i-1])
                    # voltage should not have decreased
                    self.assertTrue(output['voltage'][i],
                                    output['voltage'][i-1])
                else:  # part 2, const voltage                
                    # current should be getting less positive
                    self.assertTrue(output['current'][i] <=
                                    output['current'][i-1],
                                    msg=(output['current'][i-2:i+10],
                                         output['time'][i-2:i+10]))
                    # voltage should decrease, then stay at 4.54
                    if output['voltage'][i-1] == 4.54:
                        self.assertEqual(output['voltage'][i],
                                         output['voltage'][i-1])
                    else:
                        self.assertTrue(output['voltage'][i] <=
                                        output['voltage'][i-1])
            # update index
            i = i + 1