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_verification_with_equivalent_circuit(self): R = 50e-3 # ohm R_L = 500 # ohm C = 3 # farad # setup EIS experiment ptree = PropertyTree() ptree.put_string('type', 'ElectrochemicalImpedanceSpectroscopy') ptree.put_double('frequency_upper_limit', 1e+4) ptree.put_double('frequency_lower_limit', 1e-6) ptree.put_int('steps_per_decade', 3) ptree.put_int('steps_per_cycle', 1024) 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) # setup equivalent circuit database device_database = PropertyTree() device_database.put_double('series_resistance', R) device_database.put_double('parallel_resistance', R_L) device_database.put_double('capacitance', C) # analytical solutions Z = {} Z['SeriesRC'] = lambda f: R + 1 / (1j * C * 2 * pi * f) Z['ParallelRC'] = lambda f: R + R_L / (1 + 1j * R_L * C * 2 * pi * f) for device_type in ['SeriesRC', 'ParallelRC']: # create a device device_database.put_string('type', device_type) device = EnergyStorageDevice(device_database) # setup experiment and measure eis.reset() eis.run(device) f = eis._data['frequency'] Z_computed = eis._data['impedance'] # compute the exact solution Z_exact = Z[device_type](f) # ensure the error is small max_phase_error_in_degree = linalg.norm( angle(Z_computed) * 180 / pi - angle(Z_exact) * 180 / pi, inf) max_magniture_error_in_decibel = linalg.norm( 20 * log10(absolute(Z_exact)) - 20 * log10(absolute(Z_computed)), inf) print(device_type) print( '-- max_phase_error_in_degree = {0}'.format(max_phase_error_in_degree)) print( '-- max_magniture_error_in_decibel = {0}'.format(max_magniture_error_in_decibel)) self.assertLessEqual(max_phase_error_in_degree, 1) self.assertLessEqual(max_magniture_error_in_decibel, 0.2)
def __init__(self, ptree): Experiment.__init__(self) self._discharge_power_lower_limit = ptree.get_double( 'discharge_power_lower_limit') self._discharge_power_upper_limit = ptree.get_double( 'discharge_power_upper_limit') self._steps_per_decade = ptree.get_int('steps_per_decade') self._min_steps_per_discharge = ptree.get_int( 'min_steps_per_discharge') self._max_steps_per_discharge = ptree.get_int( 'max_steps_per_discharge') self._time_step_initial_guess = ptree.get_double('time_step') self._ptree = copy(ptree) self.reset()
def test_abstract_class(self): # Declare a concrete Experiment class DummyExperiment(Experiment): def __new__(cls, *args, **kwargs): return object.__new__(DummyExperiment) def __init__(self, ptree): Experiment.__init__(self) # Do not forget to register it to the builders dictionary. Observable._builders['Dummy'] = DummyExperiment # Construct directly via DummyExperiment with a PropertyTree as a # positional arguemnt ptree = PropertyTree() dummy = DummyExperiment(ptree) # ... or directly via Experiment by specifying the ``type`` of # Experiment. ptree.put_string('type', 'Dummy') dummy = Experiment(ptree) # The method run() must be overloaded. self.assertRaises(RuntimeError, dummy.run, None) # Override the method run(). def run(self, device): pass DummyExperiment.run = run # Now calling it without raising an error. dummy.run(None)
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_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_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 __init__(self, ptree): Experiment.__init__(self)