def test_pickle_support(self): import pickle src = PropertyTree() src.put_double('pi', 3.14) src.put_string('greet', 'bonjour') p = pickle.dumps(src) dst = pickle.loads(p) self.assertEqual(dst.get_double('pi'), 3.14) self.assertEqual(dst.get_string('greet'), 'bonjour')
def test_retrieve_data(self): ptree = PropertyTree() ptree.put_string('type', 'SeriesRC') ptree.put_double('series_resistance', 50e-3) ptree.put_double('capacitance', 3) device = EnergyStorageDevice(ptree) ptree = PropertyTree() ptree.put_string('type', 'RagoneAnalysis') ptree.put_double('discharge_power_lower_limit', 1e-1) ptree.put_double('discharge_power_upper_limit', 1e+1) ptree.put_int('steps_per_decade', 1) ptree.put_double('initial_voltage', 2.1) ptree.put_double('final_voltage', 0.7) ptree.put_double('time_step', 1.5) ptree.put_int('min_steps_per_discharge', 20) ptree.put_int('max_steps_per_discharge', 30) ragone = Experiment(ptree) with File('trash.hdf5', 'w') as fout: ragone.run(device, fout) performance_data = ragone._data fin = File('trash.hdf5', 'r') retrieved_data = retrieve_performance_data(fin) fin.close() # a few digits are lost when power is converted to string self.assertLess( linalg.norm(performance_data['power'] - retrieved_data['power'], inf), 1e-12) self.assertEqual( linalg.norm(performance_data['energy'] - retrieved_data['energy'], inf), 0.0) # TODO: probably want to move this into its own test ragoneplot = RagonePlot("ragone.png") ragoneplot.update(ragone) # check reset reinitialize the time step and empty the data ragone.reset() self.assertEqual(ragone._ptree.get_double('time_step'), 1.5) self.assertFalse(ragone._data['power']) self.assertFalse(ragone._data['energy'])
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_retrieve_data(self): ptree = PropertyTree() ptree.put_string('type', 'SeriesRC') ptree.put_double('series_resistance', 100e-3) ptree.put_double('capacitance', 2.5) device = EnergyStorageDevice(ptree) ptree = PropertyTree() ptree.put_string('type', 'ElectrochemicalImpedanceSpectroscopy') ptree.put_double('frequency_upper_limit', 1e+2) ptree.put_double('frequency_lower_limit', 1e-1) ptree.put_int('steps_per_decade', 1) ptree.put_int('steps_per_cycle', 64) ptree.put_int('cycles', 2) ptree.put_int('ignore_cycles', 1) ptree.put_double('dc_voltage', 0) ptree.put_string('harmonics', '3') ptree.put_string('amplitudes', '5e-3') ptree.put_string('phases', '0') eis = Experiment(ptree) with File('trash.hdf5', 'w') as fout: eis.run(device, fout) spectrum_data = eis._data with File('trash.hdf5', 'r') as fin: retrieved_data = retrieve_impedance_spectrum(fin) print(spectrum_data['impedance'] - retrieved_data['impedance']) print(retrieved_data) self.assertEqual( linalg.norm( spectrum_data['frequency'] - retrieved_data['frequency'], inf), 0.0) # not sure why we don't get equality for the impedance self.assertLess( linalg.norm( spectrum_data['impedance'] - retrieved_data['impedance'], inf), 1e-10)
def test_force_discharge(self): ptree = PropertyTree() ptree.put_string('mode', 'constant_voltage') ptree.put_double('voltage', 0.0) ptree.put_string('end_criterion', 'current_less_than') ptree.put_double('current_limit', 1e-5) ptree.put_double('time_step', 1.0) stage = Stage(ptree) data = initialize_data() steps = stage.run(device, data) self.assertGreaterEqual(steps, 1) self.assertEqual(steps, len(data['time'])) self.assertAlmostEqual(data['voltage'][-1], 0.0) self.assertLessEqual(data['current'][-1], 1e-5)
def test_constant_current_charge_for_given_time(self): ptree = PropertyTree() ptree.put_string('mode', 'constant_current') ptree.put_double('current', 5e-3) ptree.put_string('end_criterion', 'time') ptree.put_double('duration', 15.0) ptree.put_double('time_step', 0.1) stage = Stage(ptree) data = initialize_data() steps = stage.run(device, data) self.assertEqual(steps, 150) self.assertEqual(steps, len(data['time'])) self.assertAlmostEqual(data['time'][-1], 15.0) self.assertAlmostEqual(data['current'][-1], 5e-3)
def test_charge_constant_current(self): ptree = PropertyTree() ptree.put_string('charge_mode', 'constant_current') ptree.put_double('charge_current', 10e-3) ptree.put_string('charge_stop_at_1', 'voltage_greater_than') ptree.put_double('charge_voltage_limit', 1.4) ptree.put_double('time_step', 0.2) charge = Charge(ptree) data = initialize_data() charge.run(device, data) self.assertAlmostEqual(data['current'][0], 10e-3) self.assertAlmostEqual(data['current'][-1], 10e-3) self.assertGreaterEqual(data['voltage'][-1], 1.4) self.assertAlmostEqual(data['time'][1] - data['time'][0], 0.2)
def test_charge_constant_voltage(self): ptree = PropertyTree() ptree.put_string('charge_mode', 'constant_voltage') ptree.put_double('charge_voltage', 1.4) ptree.put_string('charge_stop_at_1', 'current_less_than') ptree.put_double('charge_current_limit', 1e-6) ptree.put_string('charge_stop_at_2', 'time') ptree.put_double('charge_max_duration', 60) ptree.put_double('time_step', 0.2) charge = Charge(ptree) data = initialize_data() charge.run(device, data) self.assertTrue(data['time'][-1] >= 60 or abs(data['current'][-1]) <= 1e-6) self.assertAlmostEqual(data['voltage'][-1], 1.4)
def test_get_array(self): ptree = PropertyTree() # array of double ptree.put_string('array_double', '3.14,1.41') array_double = ptree.get_array_double('array_double') self.assertEqual(array_double, [3.14, 1.41]) # ... string ptree.put_string('array_int', '1,2,3') array_int = ptree.get_array_int('array_int') self.assertEqual(array_int, [1, 2, 3]) # ... int ptree.put_string('array_string', 'uno,dos,tres,cuatro') array_string = ptree.get_array_string('array_string') self.assertEqual(array_string, ['uno', 'dos', 'tres', 'cuatro']) # ... bool ptree.put_string('array_bool', 'true,FALSE,False') array_bool = ptree.get_array_bool('array_bool') self.assertEqual(array_bool, [True, False, False])
def test_time_steps(self): ptree = PropertyTree() ptree.put_int('stages', 2) ptree.put_int('cycles', 1) ptree.put_double('time_step', 1.0) ptree.put_string('stage_0.mode', 'hold') ptree.put_string('stage_0.end_criterion', 'time') ptree.put_double('stage_0.duration', 2.0) ptree.put_string('stage_1.mode', 'rest') ptree.put_string('stage_1.end_criterion', 'time') ptree.put_double('stage_1.duration', 1.0) ptree.put_double('stage_1.time_step', 0.1) multi = MultiStage(ptree) data = initialize_data() steps = multi.run(device, data) self.assertEqual(steps, 12) self.assertEqual(steps, len(data['time'])) self.assertAlmostEqual(data['time'][5], 2.4) self.assertAlmostEqual(data['voltage'][0], data['voltage'][1]) self.assertAlmostEqual(data['current'][3], 0.0)
def test_setup_frequency_range(self): ptree = PropertyTree() ptree.put_string('type', 'ElectrochemicalImpedanceSpectroscopy') # specify the upper and lower bounds of the range # the number of points per decades controls the spacing on the log # scale ptree.put_double('frequency_upper_limit', 1e+2) ptree.put_double('frequency_lower_limit', 1e-1) ptree.put_int('steps_per_decade', 3) eis = Experiment(ptree) print(eis._frequencies) f = eis._frequencies self.assertEqual(len(f), 10) self.assertAlmostEqual(f[0], 1e+2) self.assertAlmostEqual(f[3], 1e+1) self.assertAlmostEqual(f[9], 1e-1) # or directly specify the frequencies frequencies = [3, 2e3, 0.1] eis = Experiment(ptree, frequencies) self.assertTrue(all(equal(frequencies, eis._frequencies)))
def test_current_limit(self): # lower ptree = PropertyTree() ptree.put_string('end_criterion', 'current_less_than') ptree.put_double('current_limit', -5e-3) self.assertRaises(RuntimeError, EndCriterion.factory, ptree) ptree.put_double('current_limit', 0.0) self.assertRaises(RuntimeError, EndCriterion.factory, ptree) ptree.put_double('current_limit', 5e-3) current_limit = EndCriterion.factory(ptree) device.evolve_one_time_step_constant_current(5.0, 0.0) self.assertTrue(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, 0.002) self.assertTrue(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, -0.001) self.assertTrue(current_limit.check(180.0, device)) device.evolve_one_time_step_constant_current(5.0, 0.005) self.assertTrue(current_limit.check(180.0, device)) device.evolve_one_time_step_constant_current(5.0, 0.007) self.assertFalse(current_limit.check(180.0, device)) device.evolve_one_time_step_constant_current(5.0, -15e3) self.assertFalse(current_limit.check(180.0, device)) # upper ptree.put_string('end_criterion', 'current_greater_than') ptree.put_double('current_limit', -5e-3) self.assertRaises(RuntimeError, EndCriterion.factory, ptree) ptree.put_double('current_limit', 0.0) self.assertRaises(RuntimeError, EndCriterion.factory, ptree) ptree.put_double('current_limit', 5e-3) current_limit = EndCriterion.factory(ptree) device.evolve_one_time_step_constant_current(5.0, -1e-3) self.assertFalse(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, 0.002) self.assertFalse(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, 0.005) self.assertTrue(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, -0.2) self.assertTrue(current_limit.check(NaN, device)) device.evolve_one_time_step_constant_current(5.0, 3.0) self.assertTrue(current_limit.check(NaN, device))
def test_compound_criterion(self): ptree = PropertyTree() ptree.put_string('end_criterion', 'compound') ptree.put_string('criterion_0.end_criterion', 'time') ptree.put_double('criterion_0.duration', 5.0) ptree.put_string('criterion_1.end_criterion', 'voltage_greater_than') ptree.put_double('criterion_1.voltage_limit', 2.0) # no default value for now self.assertRaises(KeyError, EndCriterion.factory, ptree) ptree.put_string('logical_operator', 'bad_operator') self.assertRaises(RuntimeError, EndCriterion.factory, ptree) ptree.put_string('logical_operator', 'or') compound_criterion = EndCriterion.factory(ptree) compound_criterion.reset(0.0, device) device.evolve_one_time_step_constant_voltage(0.1, 1.0) self.assertFalse(compound_criterion.check(3.0, device)) self.assertTrue(compound_criterion.check(5.0, device)) device.evolve_one_time_step_constant_voltage(0.1, 2.0) self.assertTrue(compound_criterion.check(3.0, device)) self.assertTrue(compound_criterion.check(5.0, device)) ptree.put_string('logical_operator', 'and') compound_criterion = EndCriterion.factory(ptree) compound_criterion.reset(0.0, device) device.evolve_one_time_step_constant_voltage(0.1, 1.0) self.assertFalse(compound_criterion.check(3.0, device)) self.assertFalse(compound_criterion.check(5.0, device)) device.evolve_one_time_step_constant_voltage(0.1, 2.0) self.assertFalse(compound_criterion.check(3.0, device)) self.assertTrue(compound_criterion.check(5.0, device)) ptree.put_string('logical_operator', 'xor') compound_criterion = EndCriterion.factory(ptree) compound_criterion.reset(0.0, device) device.evolve_one_time_step_constant_voltage(0.1, 1.0) self.assertFalse(compound_criterion.check(3.0, device)) self.assertTrue(compound_criterion.check(5.0, device)) device.evolve_one_time_step_constant_voltage(0.1, 2.0) self.assertTrue(compound_criterion.check(3.0, device)) self.assertFalse(compound_criterion.check(5.0, device))
def test_builders(self): for AbstractClass in [Observer, Observable]: # AbstractClass takes a PropertyTree as argument. self.assertRaises(TypeError, AbstractClass) # The PropertyTree must specify what concrete class derived from # AbstractClass to instantiate. ptree = PropertyTree() self.assertRaises(KeyError, AbstractClass, ptree) # The derived concrete class must be registerd in the dictionary # that holds the builders. ptree.put_string('type', 'Invalid') self.assertRaises(KeyError, AbstractClass, ptree) # Now declare a concrete class. class ConcreteClass(AbstractClass): def __new__(cls, *args, **kwargs): return object.__new__(ConcreteClass) def __init__(*args, **kwargs): pass # Here is how to register a derived concrete class to the base # abstract class. AbstractClass._builders['ConcreteClass'] = ConcreteClass # Now instantiation works. ptree.put_string('type', 'ConcreteClass') AbstractClass(ptree) # Also can build directly from derived class. ConcreteClass() # Remove from the dictionary. del AbstractClass._builders['ConcreteClass'] self.assertRaises(KeyError, AbstractClass, ptree)
def test_voltage_limit(self): ptree = PropertyTree() ptree.put_double('voltage_limit', 1.7) # upper limit ptree.put_string('end_criterion', 'voltage_greater_than') voltage_limit = EndCriterion.factory(ptree) voltage_limit.reset(5.0, device) device.evolve_one_time_step_constant_voltage(0.2, 1.3) self.assertFalse(voltage_limit.check(0.0, device)) self.assertFalse(voltage_limit.check(60.0, device)) device.evolve_one_time_step_constant_voltage(0.2, 1.7) self.assertTrue(voltage_limit.check(45.0, device)) device.evolve_one_time_step_constant_voltage(0.2, 2.1) self.assertTrue(voltage_limit.check(45.0, device)) # lower limit ptree.put_string('end_criterion', 'voltage_less_than') voltage_limit = EndCriterion.factory(ptree) voltage_limit.reset(0.0, device) device.evolve_one_time_step_constant_voltage(0.2, 1.3) self.assertTrue(voltage_limit.check(0.0, device)) device.evolve_one_time_step_constant_voltage(0.2, 1.7) self.assertTrue(voltage_limit.check(45.0, device)) device.evolve_one_time_step_constant_voltage(0.2, 2.1) self.assertFalse(voltage_limit.check(45.0, device))
def test_fourier_analysis(self): ptree = PropertyTree() ptree.put_int('steps_per_cycle', 3) ptree.put_int('cycles', 1) ptree.put_int('ignore_cycles', 0) ptree.put_string('harmonics', '1') # uninitialized data data = {} self.assertRaises(KeyError, fourier_analysis, data, ptree) # empty data data = initialize_data() self.assertRaises(IndexError, fourier_analysis, data, ptree) # bad data data['time'] = array([1, 2, 3], dtype=float) data['current'] = array([4, 5, 6], dtype=float) data['voltage'] = array([7, 8], dtype=float) self.assertRaises(AssertionError, fourier_analysis, data, ptree) # poor data (size not a power of 2) data['voltage'] = array([7, 8, 9], dtype=float) with catch_warnings(): simplefilter("error") self.assertRaises(RuntimeWarning, fourier_analysis, data, ptree) # data unchanged after analyze dummy = array([1, 2, 3, 4, 5, 6, 7, 8], dtype=float) data['time'] = dummy data['current'] = dummy data['voltage'] = dummy # ptree needs to be updated self.assertRaises(AssertionError, fourier_analysis, data, ptree) ptree.put_int('steps_per_cycle', 4) ptree.put_int('cycles', 2) ptree.put_int('ignore_cycles', 0) fourier_analysis(data, ptree) self.assertTrue(all(equal(data['time'], dummy))) self.assertTrue(all(equal(data['current'], dummy))) self.assertTrue(all(equal(data['voltage'], dummy)))
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
# Copyright (c) 2016, the Cap authors. # # This file is subject to the Modified BSD License and may not be distributed # without copyright and license information. Please refer to the file LICENSE # for the text and further information on this license. from pycap import PropertyTree, EnergyStorageDevice from pycap import Charge from pycap import initialize_data from mpi4py import MPI import unittest comm = MPI.COMM_WORLD filename = 'series_rc.info' ptree = PropertyTree() ptree.parse_info(filename) device = EnergyStorageDevice(ptree, comm) class capChargeTestCase(unittest.TestCase): def test_charge_constant_current(self): ptree = PropertyTree() ptree.put_string('charge_mode', 'constant_current') ptree.put_double('charge_current', 10e-3) ptree.put_string('charge_stop_at_1', 'voltage_greater_than') ptree.put_double('charge_voltage_limit', 1.4) ptree.put_double('time_step', 0.2) charge = Charge(ptree) data = initialize_data() charge.run(device, data) self.assertAlmostEqual(data['current'][0], 10e-3)
def test_constructor(self): self.assertRaises(TypeError, EndCriterion) self.assertRaises(RuntimeError, EndCriterion, PropertyTree())
def test_invalid_end_criterion(self): ptree = PropertyTree() ptree.put_string('end_criterion', 'bad_name') self.assertRaises(RuntimeError, EndCriterion.factory, ptree)
def test_always_statisfied(self): ptree = PropertyTree() ptree.put_string('end_criterion', 'skip') always_statisfied = EndCriterion.factory(ptree) always_statisfied.reset(0.0, device) self.assertTrue(always_statisfied.check(NaN, device))
def test_never_statisfied(self): ptree = PropertyTree() ptree.put_string('end_criterion', 'none') never_statisfied = EndCriterion.factory(ptree) never_statisfied.reset(0.0, device) self.assertFalse(never_statisfied.check(NaN, device))
def test_rest(self): ptree = PropertyTree() ptree.put_string('mode', 'rest') evolve_one_time_step = TimeEvolution.factory(ptree) evolve_one_time_step(device, 0.1) self.assertEqual(device.get_current(), 0.0)
def test_invalid_time_evolution(self): ptree = PropertyTree() ptree.put_string('mode', 'unexpected') self.assertRaises(RuntimeError, TimeEvolution.factory, ptree)
def test_constructor(self): self.assertRaises(TypeError, TimeEvolution) self.assertRaises(RuntimeError, TimeEvolution, PropertyTree())
#!/usr/bin/env python from puq import dump_hdf5 from optparse import OptionParser from pycap import PropertyTree, EnergyStorageDevice from pycap import measure_impedance_spectrum from numpy import real, imag, log10, absolute, angle # read uq database uq_database = PropertyTree() uq_database.parse_xml('uq.xml') # get number of parameters params = uq_database.get_int('uq.params') # usage usage = 'usage: %prog' for p in range(params): usage += ' --param_' + str(p) + ' val_' + str(p) parser = OptionParser(usage) # register options for p in range(params): parser.add_option('--param_' + str(p), type=float) # parse the command line arguments (options, args) = parser.parse_args() # make device database device_database = PropertyTree() device_database.parse_xml('super_capacitor.xml') # adjust the parameters in the database options_dict = vars(options) for var in options_dict:
def run(): # parse uq database input_database = PropertyTree() input_database.parse_xml('uq.xml') uq_database = input_database.get_child('uq') # declare parameters params = uq_database.get_int('params') parameter_list = [] for p in range(params): parameter_database = uq_database.get_child('param_' + str(p)) distribution_type = parameter_database.get_string('distribution_type') parameter_name = parameter_database.get_string('name') if distribution_type == 'uniform': parameter_range = parameter_database.get_array_double('range') parameter_list.append( UniformParameter('param_' + str(p), parameter_name, min=parameter_range[0], max=parameter_range[1])) elif distribution_type == 'normal': parameter_mean = parameter_database.get_double('mean') parameter_standard_deviation = parameter_database.get_double( 'standard_deviation') parameter_list.append( NormalParameter('param_' + str(p), parameter_name, mean=parameter_mean, dev=parameter_standard_deviation)) else: raise RuntimeError('invalid distribution type ' + distribution_type + ' for param_' + str(p)) # create a host host_database = uq_database.get_child('host') host_type = host_database.get_string('type') if host_type == "Interactive": host = InteractiveHost( cpus=host_database.get_int_with_default_value('cpus', 1), cpus_per_node=host_database.get_int_with_default_value( 'cpus_per_node', 0)) elif host_type == "PBS": host = PBSHost( host_database.get_string('env'), cpus=host_database.get_int_with_default_value('cpus', 0), cpus_per_node=host_database.get_int_with_default_value( 'cpus_per_node', 0), qname=host_database.get_string_with_default_value( 'qname', 'standby'), walltime=host_database.get_string_with_default_value( 'walltime', '1:00:00'), modules=host_database.get_string_with_default_value('modules', ''), pack=host_database.get_int_with_default_value('pack', 1), qlimit=host_database.get_int_with_default_value('qlimit', 200)) else: raise RuntimeError('invalid host type ' + host_type) # pick UQ method method = uq_database.get_string('method') if method == 'SmolyakSparseGrid': level = uq_database.get_int('level') uq = Smolyak(parameter_list, level=level) elif method == 'MonteCarlo': samples = uq_database.get_int('samples') uq = MonteCarlo(parameter_list, num=samples) elif method == 'LatinHypercubeSampling': samples = uq_database.get_int('samples') uq = LHS(parameter_list, num=samples) else: raise RuntimeError('invalid UQ method ' + method) # make a test program test_program_database = uq_database.get_child('test_program') description = test_program_database.get_string('description') executable_name = test_program_database.get_string('executable') for p in range(params): executable_name += ' --param_' + str(p) + ' $param_' + str(p) prog = TestProgram(exe=executable_name, desc=description) # run return Sweep(uq, host, prog)