Beispiel #1
0
 def test_from_maccor_insufficient_interpolation_length(self):
     md = MaccorDatapath.from_file(self.broken_file)
     vrange, num_points, nominal_capacity, fast_charge, diag = md.determine_structuring_parameters()
     self.assertEqual(diag['parameter_set'], 'Tesla21700')
     diag_interp = md.interpolate_diagnostic_cycles(diag, resolution=1000, v_resolution=0.0005)
     self.assertEqual(np.around(diag_interp[diag_interp.cycle_index == 1].charge_capacity.median(), 3),
                      np.around(0.6371558214610992, 3))
Beispiel #2
0
 def test_step_is_waveform(self):
     md = MaccorDatapath.from_file(self.waveform_file)
     df = md.raw_data
     self.assertTrue(df.loc[df.cycle_index == 6].
                     groupby("step_index").apply(step_is_waveform_dchg).any())
     self.assertFalse(df.loc[df.cycle_index == 6].
                     groupby("step_index").apply(step_is_waveform_chg).any())
     self.assertFalse(df.loc[df.cycle_index == 3].
                     groupby("step_index").apply(step_is_waveform_dchg).any())
Beispiel #3
0
 def test_waveform_charge_discharge_capacity(self):
     md = MaccorDatapath.from_file(self.waveform_file)
     df = md.raw_data
     cycle_sign = np.sign(np.diff(df["cycle_index"]))
     capacity_sign = np.sign(np.diff(df["charge_capacity"]))
     self.assertTrue(
         np.all(capacity_sign >= -cycle_sign)
     )  # Capacity increases throughout cycle
     capacity_sign = np.sign(np.diff(df["discharge_capacity"]))
     self.assertTrue(
         np.all(capacity_sign >= -cycle_sign)
     )
Beispiel #4
0
    def test_interpolate_waveform_discharge_cycles(self):
        md = MaccorDatapath.from_file(self.waveform_file)
        all_interpolated = md.interpolate_cycles()
        all_interpolated = all_interpolated[(all_interpolated.step_type == "discharge")]
        self.assertTrue(all_interpolated.columns[0] == 'test_time')
        subset_interpolated = all_interpolated[all_interpolated.cycle_index==6]

        df = md.raw_data
        self.assertEqual(subset_interpolated.test_time.min(),
                         df.loc[(df.cycle_index == 6) &
                                (df.step_index == 33)].test_time.min())
        self.assertEqual(subset_interpolated[subset_interpolated.cycle_index == 6].shape[0], 1000)
Beispiel #5
0
    def test_get_quantity_sum(self):
        md = MaccorDatapath.from_file(self.diagnostics_file)

        cycle_sign = np.sign(np.diff(md.raw_data["cycle_index"]))
        capacity_sign = np.sign(np.diff(md.raw_data["charge_capacity"]))
        self.assertTrue(
            np.all(capacity_sign >= -cycle_sign)
        )  # Capacity increases throughout cycle
        capacity_sign = np.sign(np.diff(md.raw_data["discharge_capacity"]))
        self.assertTrue(
            np.all(capacity_sign >= -cycle_sign)
        )  # Capacity increases throughout cycle
Beispiel #6
0
    def test_from_file(self):

        for file in (self.good_file, self.timestamp_file, self.timezone_file):
            md = MaccorDatapath.from_file(file)
            self.assertEqual(md.paths.get("raw"), file)
            self.assertEqual(md.paths.get("metadata"), file)

            if file == self.good_file:
                self.assertTupleEqual(md.raw_data.shape, (11669, 40))
                self.assertEqual(70, md.metadata.channel_id)
            elif file == self.timestamp_file:
                self.assertTupleEqual(md.raw_data.shape, (333, 44))
                self.assertEqual(52, md.metadata.channel_id)
            else:
                self.assertTupleEqual(md.raw_data.shape, (2165, 44))
                self.assertEqual(10, md.metadata.channel_id)

            self.assertEqual(
                set(md.metadata.raw.keys()),
                {
                    "barcode",
                    "_today_datetime",
                    "start_datetime",
                    "filename",
                    "protocol",
                    "channel_id",
                },
            )

            # Quick test to see whether columns get recasted
            self.assertTrue(
                {
                    "data_point",
                    "cycle_index",
                    "step_index",
                    "voltage",
                    "current",
                    "charge_capacity",
                    "discharge_capacity",
                }
                < set(md.raw_data.columns)
            )
Beispiel #7
0
def auto_load(filename):
    """Load any supported raw battery cycler file to the correct Datapath automatically.

    Matches raw file patterns to the correct datapath and returns the datapath object.

    Example:
        auto_load("2017-05-09_test-TC-contact_CH33.csv")

        >>> <ArbinDatapath object>

        auto_load("PreDiag_000287_000128short.092")

        >>> <MaccorDatapath object>

    Args:
        filename (str, Pathlike): string corresponding to battery cycler file filename.

    Returns:
        (beep.structure.base.BEEPDatapath): The datapath child class corresponding to this file.

    """
    if re.match(ARBIN_CONFIG["file_pattern"], filename) or re.match(
            FastCharge_CONFIG["file_pattern"], filename):
        return ArbinDatapath.from_file(filename)
    elif re.match(MACCOR_CONFIG["file_pattern"], filename) or re.match(
            xTesladiag_CONFIG["file_pattern"], filename):
        return MaccorDatapath.from_file(filename)
    elif re.match(INDIGO_CONFIG["file_pattern"], filename):
        return IndigoDatapath.from_file(filename)
    elif re.match(BIOLOGIC_CONFIG["file_pattern"], filename):
        return BiologicDatapath.from_file(filename)
    elif re.match(NEWARE_CONFIG["file_pattern"], filename):
        return NewareDatapath.from_file(filename)
    elif re.match(BatteryArchiveDatapath.FILE_PATTERN, filename):
        return BatteryArchiveDatapath.from_file(filename)
    else:
        raise ValueError(
            "{} does not match any known file pattern".format(filename))
Beispiel #8
0
    def test_raw_to_features(self):

        download_s3_object(bucket=self.maccor_file_w_parameters_s3["bucket"],
                           key=self.maccor_file_w_parameters_s3["key"],
                           destination_path=self.maccor_file_w_parameters)

        dp = MaccorDatapath.from_file(self.maccor_file_w_parameters)
        dp.autostructure()
        processed_run_path = os.path.join(TEST_FILE_DIR,
                                          "processed_diagnostic.json")

        # Dump to the structured file and check the file size
        dumpfn(dp, processed_run_path)

        dp = loadfn(processed_run_path)

        for fclass in (
                DeltaQFastCharge,
                CycleSummaryStats,
                TrajectoryFastCharge,
                DiagnosticSummaryStats,
                HPPCResistanceVoltageFeatures,
        ):
            f = fclass(dp)
            self.assertTrue(f.validate()[0])
            f.create_features()

            if fclass.__class__.__name__ == "HPPCResistanceVoltageFeatures":
                self.assertAlmostEqual(f.features['r_c_0s_00'].iloc[0],
                                       -0.159771397, 5)
                self.assertAlmostEqual(f.features['r_c_0s_10'].iloc[0],
                                       -0.143679, 5)
                self.assertAlmostEqual(f.features['r_c_0s_20'].iloc[0],
                                       -0.146345, 5)
                self.assertAlmostEqual(f.features['D_6'].iloc[0], -0.167919, 5)
                self.assertAlmostEqual(f.features['D_7'].iloc[0], 0.094136, 5)
                self.assertAlmostEqual(f.features['D_8'].iloc[0], 0.172496, 5)
Beispiel #9
0
    def test_raw_to_features(self):
        os.environ["BEEP_PROCESSING_DIR"] = TEST_FILE_DIR

        download_s3_object(bucket=self.maccor_file_w_parameters_s3["bucket"],
                           key=self.maccor_file_w_parameters_s3["key"],
                           destination_path=self.maccor_file_w_parameters)

        with ScratchDir("."):
            os.environ["BEEP_PROCESSING_DIR"] = TEST_FILE_DIR
            # os.environ['BEEP_PROCESSING_DIR'] = os.getcwd()
            dp = MaccorDatapath.from_file(self.maccor_file_w_parameters)
            dp.autostructure()
            processed_run_path = os.path.join(TEST_FILE_DIR,
                                              "processed_diagnostic.json")
            # Dump to the structured file and check the file size
            dumpfn(dp, processed_run_path)
            # Create dummy json obj
            json_obj = {
                "file_list": [processed_run_path],
                "run_list": [0],
            }
            json_string = json.dumps(json_obj)

            newjsonpaths = process_file_list_from_json(
                json_string, processed_dir=os.getcwd())

            reloaded = json.loads(newjsonpaths)

            import pprint
            pprint.pprint(reloaded)

            result_list = ['success'] * 7
            self.assertEqual(reloaded['result_list'], result_list)
            rpt_df = loadfn(reloaded['file_list'][0])
            self.assertEqual(
                np.round(rpt_df.X['m0_Amp_rpt_0.2C_1'].iloc[0], 6), 0.867371)
Beispiel #10
0
    def test_interpolate_cycles(self):
        md = MaccorDatapath.from_file(self.good_file)
        all_interpolated = md.interpolate_cycles(
            v_range=[3.0, 4.2], resolution=10000
        )

        self.assertSetEqual(set(all_interpolated.columns.tolist()),
                            {'voltage',
                             'test_time',
                             'discharge_capacity',
                             'discharge_energy',
                             'current',
                             'charge_capacity',
                             'charge_energy',
                             'internal_resistance',
                             'temperature',
                             'cycle_index',
                             'step_type'}
                            )
        interp2 = all_interpolated[
            (all_interpolated.cycle_index == 2)
            & (all_interpolated.step_type == "discharge")
            ].sort_values("discharge_capacity")
        interp3 = all_interpolated[
            (all_interpolated.cycle_index == 1)
            & (all_interpolated.step_type == "charge")
            ].sort_values("charge_capacity")

        self.assertTrue(interp3.current.mean() > 0)
        self.assertEqual(len(interp3.voltage), 10000)
        self.assertEqual(interp3.voltage.max(), np.float32(4.100838))
#        self.assertEqual(interp3.voltage.min(), np.float32(3.3334765)) # 3.437705 in python3.9
        np.testing.assert_almost_equal(
            interp3[
                interp3.charge_capacity <= interp3.charge_capacity.median()
                ].current.iloc[0],
            2.423209,
            decimal=6,
        )

        df = md.raw_data
        cycle_2 = df[df["cycle_index"] == 2]
        discharge = cycle_2[cycle_2.step_index == 12]
        discharge = discharge.sort_values("discharge_capacity")

        acceptable_error = 0.01
        acceptable_error_offest = 0.001
        voltages_to_check = [3.3, 3.2, 3.1]
        columns_to_check = [
            "voltage",
            "current",
            "discharge_capacity",
            "charge_capacity",
        ]
        for voltage_check in voltages_to_check:
            closest_interp2_index = interp2.index[
                (interp2["voltage"] - voltage_check).abs().min()
                == (interp2["voltage"] - voltage_check).abs()
                ]
            closest_interp2_match = interp2.loc[closest_interp2_index]
            closest_discharge_index = discharge.index[
                (discharge["voltage"] - voltage_check).abs().min()
                == (discharge["voltage"] - voltage_check).abs()
                ]
            closest_discharge_match = discharge.loc[closest_discharge_index]
            for column_check in columns_to_check:
                off_by = (
                        closest_interp2_match.iloc[0][column_check]
                        - closest_discharge_match.iloc[0][column_check]
                )
                self.assertLessEqual(np.abs(off_by),
                        np.abs(closest_interp2_match.iloc[0][column_check])
                        * acceptable_error
                        + acceptable_error_offest)
Beispiel #11
0
    def test_get_diagnostic(self):
        maccor_file_w_parameters_s3 = {
            "bucket": "beep-sync-test-stage",
            "key": "big_file_tests/PreDiag_000287_000128.092"
        }

        maccor_file_w_parameters = os.path.join(TEST_FILE_DIR,
                                                "PreDiag_000287_000128.092")

        download_s3_object(bucket=maccor_file_w_parameters_s3["bucket"],
                           key=maccor_file_w_parameters_s3["key"],
                           destination_path=maccor_file_w_parameters)

        md = MaccorDatapath.from_file(maccor_file_w_parameters)

        (
            v_range,
            resolution,
            nominal_capacity,
            full_fast_charge,
            diagnostic_available,
        ) = md.determine_structuring_parameters()

        self.assertEqual(nominal_capacity, 4.84)
        # self.assertEqual(v_range, [2.7, 4.2]) # This is an older assertion, value changed when
        # different cell types were added

        self.assertEqual(v_range, [2.5, 4.2])
        self.assertEqual(
            diagnostic_available["cycle_type"],
            ["reset", "hppc", "rpt_0.2C", "rpt_1C", "rpt_2C"],
        )
        diag_summary = md.summarize_diagnostic(diagnostic_available)

        reg_summary = md.summarize_cycles(diagnostic_available)
        self.assertEqual(len(reg_summary.cycle_index.tolist()), 230)
        self.assertEqual(reg_summary.cycle_index.tolist()[:10],
                         [0, 6, 7, 8, 9, 10, 11, 12, 13, 14])

        # Check data types are being set correctly for diagnostic summary
        diag_dyptes = diag_summary.dtypes.tolist()
        diag_columns = diag_summary.columns.tolist()
        diag_dyptes = [str(dtyp) for dtyp in diag_dyptes]
        for indx, col in enumerate(diag_columns):
            self.assertEqual(diag_dyptes[indx],
                             STRUCTURE_DTYPES["diagnostic_summary"][col])

        self.assertEqual(
            diag_summary.cycle_index.tolist(),
            [
                1, 2, 3, 4, 5, 36, 37, 38, 39, 40, 141, 142, 143, 144, 145,
                246, 247
            ],
        )
        self.assertEqual(
            diag_summary.cycle_type.tolist(),
            [
                "reset",
                "hppc",
                "rpt_0.2C",
                "rpt_1C",
                "rpt_2C",
                "reset",
                "hppc",
                "rpt_0.2C",
                "rpt_1C",
                "rpt_2C",
                "reset",
                "hppc",
                "rpt_0.2C",
                "rpt_1C",
                "rpt_2C",
                "reset",
                "hppc",
            ],
        )
        self.assertEqual(diag_summary.paused.max(), 0)
        diag_interpolated = md.interpolate_diagnostic_cycles(
            diagnostic_available, resolution=1000)

        # Check data types are being set correctly for interpolated data
        diag_dyptes = diag_interpolated.dtypes.tolist()
        diag_columns = diag_interpolated.columns.tolist()
        diag_dyptes = [str(dtyp) for dtyp in diag_dyptes]
        for indx, col in enumerate(diag_columns):
            self.assertEqual(diag_dyptes[indx],
                             STRUCTURE_DTYPES["diagnostic_interpolated"][col])

        # Provide visual inspection to ensure that diagnostic interpolation is being done correctly
        diag_cycle = diag_interpolated[
            (diag_interpolated.cycle_type == "rpt_0.2C")
            & (diag_interpolated.step_type == 1)]
        self.assertEqual(diag_cycle.cycle_index.unique().tolist(),
                         [3, 38, 143])
        plt.figure()
        plt.plot(diag_cycle.discharge_capacity, diag_cycle.voltage)
        plt.savefig(
            os.path.join(TEST_FILE_DIR,
                         "discharge_capacity_interpolation.png"))
        plt.figure()
        plt.plot(diag_cycle.voltage, diag_cycle.discharge_dQdV)
        plt.savefig(
            os.path.join(TEST_FILE_DIR, "discharge_dQdV_interpolation.png"))

        self.assertEqual(len(diag_cycle.index), 3000)

        hppcs = diag_interpolated[(diag_interpolated.cycle_type == "hppc")
                                  & pd.isnull(diag_interpolated.current)]
        self.assertEqual(len(hppcs), 0)

        hppc_dischg1 = diag_interpolated[
            (diag_interpolated.cycle_index == 37)
            & (diag_interpolated.step_type == 2)
            & (diag_interpolated.step_index_counter == 3)
            & ~pd.isnull(diag_interpolated.current)]

        plt.figure()
        plt.plot(hppc_dischg1.test_time, hppc_dischg1.voltage)
        plt.savefig(os.path.join(TEST_FILE_DIR, "hppc_discharge_pulse_1.png"))
        self.assertEqual(len(hppc_dischg1), 176)

        # processed_cycler_run = cycler_run.to_processed_cycler_run()
        md.autostructure()
        self.assertNotIn(
            diag_summary.cycle_index.tolist(),
            md.structured_data.cycle_index.unique(),
        )
        self.assertEqual(
            reg_summary.cycle_index.tolist(),
            md.structured_summary.cycle_index.tolist(),
        )

        processed_cycler_run_loc = os.path.join(TEST_FILE_DIR,
                                                "processed_diagnostic.json")
        # Dump to the structured file and check the file size
        # File size had to be incteased as datapath dump includes ALL data now
        dumpfn(md, processed_cycler_run_loc)
        proc_size = os.path.getsize(processed_cycler_run_loc)
        self.assertLess(proc_size, 260000000)

        # Reload the structured file and check for errors
        test = loadfn(processed_cycler_run_loc)
        self.assertIsInstance(test.diagnostic_summary, pd.DataFrame)
        diag_dyptes = test.diagnostic_summary.dtypes.tolist()
        diag_columns = test.diagnostic_summary.columns.tolist()
        diag_dyptes = [str(dtyp) for dtyp in diag_dyptes]
        for indx, col in enumerate(diag_columns):
            self.assertEqual(diag_dyptes[indx],
                             STRUCTURE_DTYPES["diagnostic_summary"][col])

        diag_dyptes = test.diagnostic_data.dtypes.tolist()
        diag_columns = test.diagnostic_data.columns.tolist()
        diag_dyptes = [str(dtyp) for dtyp in diag_dyptes]
        for indx, col in enumerate(diag_columns):
            self.assertEqual(diag_dyptes[indx],
                             STRUCTURE_DTYPES["diagnostic_interpolated"][col])

        self.assertEqual(test.structured_summary.cycle_index.tolist()[:10],
                         [0, 6, 7, 8, 9, 10, 11, 12, 13, 14])

        plt.figure()

        single_charge = test.structured_data[
            (test.structured_data.step_type == "charge")
            & (test.structured_data.cycle_index == 25)]
        self.assertEqual(len(single_charge.index), 1000)
        plt.plot(single_charge.charge_capacity, single_charge.voltage)
        plt.savefig(
            os.path.join(TEST_FILE_DIR,
                         "charge_capacity_interpolation_regular_cycle.png"))

        os.remove(processed_cycler_run_loc)