Exemplo n.º 1
0
def generate_protocol_files_from_csv(csv_filename, output_directory=None):

    """
    Generates a set of protocol files from csv filename input by
    reading protocol file input corresponding to each line of
    the csv file. Writes a csv file that.

    Args:
        csv_filename (str): CSV containing protocol file parameters.
        output_directory (str): directory in which to place the output files
    """
    # Read csv file
    protocol_params_df = pd.read_csv(csv_filename)

    new_files = []
    names = []
    result = ""
    message = {"comment": "", "error": ""}
    if output_directory is None:
        output_directory = PROCEDURE_TEMPLATE_DIR
    for index, protocol_params in protocol_params_df.iterrows():
        template = protocol_params["template"]
        # Filename for the output
        filename_prefix = "_".join(
            [
                protocol_params["project_name"],
                "{:06d}".format(protocol_params["seq_num"]),
            ]
        )

        # Switch for template invocation
        if template == "EXP.000":
            protocol = Procedure.from_exp(
                **protocol_params[["cutoff_voltage", "charge_rate", "discharge_rate"]]
            )
            filename = "{}.000".format(filename_prefix)
            filename = os.path.join(output_directory, "procedures", filename)
        elif template == "diagnosticV2.000":
            diag_params_df = pd.read_csv(
                os.path.join(PROCEDURE_TEMPLATE_DIR, "PreDiag_parameters - DP.csv")
            )
            diagnostic_params = diag_params_df[
                diag_params_df["diagnostic_parameter_set"]
                == protocol_params["diagnostic_parameter_set"]
            ].squeeze()

            # TODO: should these be separated?
            protocol = Procedure.from_regcyclev2(protocol_params)
            protocol.add_procedure_diagcyclev2(
                protocol_params["capacity_nominal"], diagnostic_params
            )
            filename = "{}.000".format(filename_prefix)
            filename = os.path.join(output_directory, "procedures", filename)
        # TODO: how are these different?
        elif template in ["diagnosticV3.000", "diagnosticV4.000"]:
            diag_params_df = pd.read_csv(
                os.path.join(PROCEDURE_TEMPLATE_DIR, "PreDiag_parameters - DP.csv")
            )
            diagnostic_params = diag_params_df[
                diag_params_df["diagnostic_parameter_set"]
                == protocol_params["diagnostic_parameter_set"]
            ].squeeze()
            template_fullpath = os.path.join(PROCEDURE_TEMPLATE_DIR, template)
            protocol = Procedure.generate_procedure_regcyclev3(index,
                                                               protocol_params,
                                                               template=template_fullpath)
            protocol.generate_procedure_diagcyclev3(
                protocol_params["capacity_nominal"], diagnostic_params
            )
            filename = "{}.000".format(filename_prefix)
            filename = os.path.join(output_directory, "procedures", filename)
        elif template == "drivingV1.000":
            diag_params_df = pd.read_csv(
                os.path.join(PROCEDURE_TEMPLATE_DIR, "PreDiag_parameters - DP.csv")
            )
            diagnostic_params = diag_params_df[
                diag_params_df["diagnostic_parameter_set"]
                == protocol_params["diagnostic_parameter_set"]
                ].squeeze()
            mwf_dir = os.path.join(output_directory, "mwf_files")
            waveform_name = insert_driving_parametersv1(protocol_params,
                                                        waveform_directory=mwf_dir)
            template_fullpath = os.path.join(PROCEDURE_TEMPLATE_DIR, template)
            protocol = Procedure.generate_procedure_drivingv1(index,
                                                              protocol_params,
                                                              waveform_name,
                                                              template=template_fullpath)
            protocol.generate_procedure_diagcyclev3(
                protocol_params["capacity_nominal"], diagnostic_params
            )
            filename = "{}.000".format(filename_prefix)
            filename = os.path.join(output_directory, "procedures", filename)
        elif template == "formationV1.mps":
            protocol = Settings.from_file(os.path.join(BIOLOGIC_TEMPLATE_DIR, template))
            protocol = protocol.formation_protocol_bcs(protocol, protocol_params)
            filename = "{}.mps".format(filename_prefix)
            filename = os.path.join(output_directory, "settings", filename)

        else:
            warnings.warn("Unsupported file template {}, skipping.".format(template))
            result = "error"
            message = {
                "comment": "Unable to find template: " + template,
                "error": "Not Found",
            }
            continue

        logger.info(filename, extra=s)
        if not os.path.isfile(filename):
            protocol.to_file(filename)
            new_files.append(filename)
            names.append(filename_prefix + "_")

        elif ".sdu" in template:
            logger.warning("Schedule file generation not yet implemented", extra=s)
            result = "error"
            message = {
                "comment": "Schedule file generation is not yet implemented",
                "error": "Not Implemented",
            }

    # This block of code produces the file containing all of the run file
    # names produced in this function call. This is to make starting tests easier
    _, namefile = os.path.split(csv_filename)
    namefile = namefile.split("_")[0] + "_names_"
    namefile = namefile + datetime.datetime.now().strftime("%Y%m%d_%H%M") + ".csv"
    with open(
        os.path.join(output_directory, "names", namefile), "w", newline=""
    ) as outputfile:
        wr = csv.writer(outputfile)
        for name in names:
            wr.writerow([name])
    outputfile.close()

    if not result:
        result = "success"
        message = {
            "comment": "Generated {} protocols".format(str(len(new_files))),
            "error": "",
        }

    return new_files, result, message
Exemplo n.º 2
0
    def test_waveform_from_csv(self):
        csv_file = os.path.join(TEST_FILE_DIR, "data-share", "raw",
                                "parameters", "Drive_parameters - GP.csv")
        protocol_params_df = pd.read_csv(csv_file)
        # Max power in watts in the profiles (should be less than max power limit on cyclers)
        MAX_PROFILE_CURRENT = 15
        MIN_PROFILE_VOLTAGE = 2.7
        MAX_PROFILE_POWER = MAX_PROFILE_CURRENT * MIN_PROFILE_VOLTAGE

        new_files = []
        names = []
        waveform_names = []
        result = ""
        message = {"comment": "", "error": ""}
        with ScratchDir(".") as scratch_dir:
            output_directory = scratch_dir
            os.makedirs(os.path.join(output_directory, "procedures"))
            for index, protocol_params in protocol_params_df.iterrows():
                template = protocol_params["template"]
                filename_prefix = "_".join([
                    protocol_params["project_name"],
                    "{:06d}".format(protocol_params["seq_num"]),
                ])
                if template == "drivingV1.000":
                    diag_params_df = pd.read_csv(
                        os.path.join(PROCEDURE_TEMPLATE_DIR,
                                     "PreDiag_parameters - DP.csv"))
                    diagnostic_params = diag_params_df[
                        diag_params_df["diagnostic_parameter_set"] ==
                        protocol_params["diagnostic_parameter_set"]].squeeze()
                    mwf_dir = os.path.join(scratch_dir, "mwf_files")
                    waveform_name = insert_driving_parametersv1(
                        protocol_params, waveform_directory=mwf_dir)
                    template_fullpath = os.path.join(PROCEDURE_TEMPLATE_DIR,
                                                     template)
                    protocol = Procedure.generate_procedure_drivingv1(
                        index,
                        protocol_params,
                        waveform_name,
                        template=template_fullpath)
                    protocol.generate_procedure_diagcyclev3(
                        protocol_params["capacity_nominal"], diagnostic_params)
                    filename = "{}.000".format(filename_prefix)
                    filename = os.path.join(output_directory, "procedures",
                                            filename)
                    waveform_names.append(os.path.split(waveform_name)[-1])

                if not os.path.isfile(filename):
                    protocol.to_file(filename)
                    new_files.append(filename)
                    names.append(filename_prefix + "_")

                waveform_df = pd.read_csv(waveform_name, sep="\t", header=None)
                power_df = waveform_df[waveform_df[1] == "P"]
                self.assertLessEqual(power_df[2].abs().max(),
                                     MAX_PROFILE_POWER)
                self.assertGreaterEqual(power_df[2].abs().max(), 0)

                current_df = waveform_df[waveform_df[1] == "I"]
                self.assertLessEqual(current_df[2].abs().max(),
                                     MAX_PROFILE_CURRENT)
                self.assertGreaterEqual(current_df[2].abs().max(), 0)

                discharge_df = waveform_df[waveform_df[0] == "D"]
                self.assertGreaterEqual(discharge_df[4].abs().max(),
                                        MIN_PROFILE_VOLTAGE)

                self.assertEqual(
                    protocol.get(
                        "MaccorTestProcedure.ProcSteps.TestStep.32.StepType"),
                    'FastWave')
                self.assertEqual(
                    protocol.get(
                        "MaccorTestProcedure.ProcSteps.TestStep.64.StepType"),
                    'FastWave')
                wave_value = os.path.split(waveform_name)[-1].split(".")[0]
                self.assertEqual(
                    protocol.get(
                        "MaccorTestProcedure.ProcSteps.TestStep.32.StepValue"),
                    wave_value)
                self.assertEqual(
                    protocol.get(
                        "MaccorTestProcedure.ProcSteps.TestStep.64.StepValue"),
                    wave_value)

            self.assertEqual(
                len(os.listdir(os.path.join(output_directory, "procedures"))),
                36)
            self.assertEqual(
                len(os.listdir(os.path.join(output_directory, "mwf_files"))),
                18)

        test_names = [
            'US06_x4_24W.MWF', 'LA4_x4_10W.MWF', 'US06_x4_32W.MWF',
            'LA4_x4_14W.MWF', 'US06_x4_40W.MWF', 'LA4_x4_18W.MWF',
            'US06_x8_24W.MWF', 'LA4_x8_10W.MWF', 'US06_x8_32W.MWF',
            'LA4_x8_14W.MWF', 'US06_x8_40W.MWF', 'LA4_x8_18W.MWF',
            'US06_x12_24W.MWF', 'LA4_x12_10W.MWF', 'US06_x12_32W.MWF',
            'LA4_x12_14W.MWF', 'US06_x12_40W.MWF', 'LA4_x12_18W.MWF',
            'US06_x4_24W.MWF', 'LA4_x4_10W.MWF', 'US06_x4_32W.MWF',
            'LA4_x4_14W.MWF', 'US06_x4_40W.MWF', 'LA4_x4_18W.MWF',
            'US06_x8_24W.MWF', 'LA4_x8_10W.MWF', 'US06_x8_32W.MWF',
            'LA4_x8_14W.MWF', 'US06_x8_40W.MWF', 'LA4_x8_18W.MWF',
            'US06_x12_24W.MWF', 'LA4_x12_10W.MWF', 'US06_x12_32W.MWF',
            'LA4_x12_14W.MWF', 'US06_x12_40W.MWF', 'LA4_x12_18W.MWF'
        ]
        self.assertListEqual(test_names, waveform_names)
Exemplo n.º 3
0
def generate_protocol_files_from_csv(csv_filename, output_directory=None):

    """
    Generates a set of protocol files from csv filename input by
    reading protocol file input corresponding to each line of
    the csv file. Writes a csv file that.

    Args:
        csv_filename (str): CSV containing protocol file parameters.
        output_directory (str): directory in which to place the output files
    """
    # Read csv file
    protocol_params_df = pd.read_csv(csv_filename)

    successfully_generated_files = []
    file_generation_failures = []
    names = []
    result = ""
    message = {"comment": "", "error": ""}
    if output_directory is None:
        output_directory = PROCEDURE_TEMPLATE_DIR

    for index, protocol_params in protocol_params_df.iterrows():
        template = protocol_params["template"]
        protocol = None
        # Filename for the output
        filename_prefix = "_".join(
            [
                protocol_params["project_name"],
                "{:06d}".format(protocol_params["seq_num"]),
            ]
        )
        if ".000" in template:  # Extension for maccor procedure files
            template_fullpath = os.path.join(PROCEDURE_TEMPLATE_DIR, template)
            template_length = template_detection(template_fullpath)
            if "diagnostic_parameter_set" in protocol_params:  # For parameters include diagnostics load those values
                diag_params_df = pd.read_csv(
                    os.path.join(PROCEDURE_TEMPLATE_DIR, "PreDiag_parameters - DP.csv")
                )
                diagnostic_params = diag_params_df[
                    diag_params_df["diagnostic_parameter_set"]
                    == protocol_params["diagnostic_parameter_set"]
                    ].squeeze()

            if template_length == 23 and template == "EXP.000":  # length and name for initial procedure files
                protocol = Procedure.from_exp(
                    **protocol_params[["cutoff_voltage", "charge_rate", "discharge_rate"]]
                )
            elif template_length == 72:  # length for V1 and V1 diagnostic templates without ending diagnostics
                protocol = Procedure.from_regcyclev2(protocol_params)
                protocol.add_procedure_diagcyclev2(
                    protocol_params["capacity_nominal"], diagnostic_params
                )
            elif template_length == 96:  # template length for diagnostic type cycling
                mwf_dir = os.path.join(output_directory, "mwf_files")
                if protocol_params["project_name"] == "RapidC":  # Project with charging waveform
                    waveform_name = insert_charging_parametersv1(protocol_params,
                                                                 waveform_directory=mwf_dir)
                    protocol = Procedure.generate_procedure_chargingv1(index,
                                                                       protocol_params,
                                                                       waveform_name,
                                                                       template=template_fullpath)
                elif protocol_params["project_name"] == "Drive":  # Project with discharging waveform
                    waveform_name = insert_driving_parametersv1(protocol_params,
                                                                waveform_directory=mwf_dir)
                    protocol = Procedure.generate_procedure_drivingv1(index,
                                                                      protocol_params,
                                                                      waveform_name,
                                                                      template=template_fullpath)
                else:  # Use the default parameterization for PreDiag/Prediction Diagnostic projects
                    protocol = Procedure.generate_procedure_regcyclev3(index,
                                                                       protocol_params,
                                                                       template=template_fullpath)
                protocol.generate_procedure_diagcyclev3(
                    protocol_params["capacity_nominal"], diagnostic_params
                )
            else:  # Case where its not possible to match the procedure template
                failure = {
                    "comment": "Unable to find template: " + template,
                    "error": "Not Found",
                }
                file_generation_failures.append(failure)
                warnings.warn("Unsupported file template {}, skipping.".format(template))
                result = "error"
                continue

            filename = "{}.000".format(filename_prefix)
            filename = os.path.join(output_directory, "procedures", filename)

        elif ".mps" in template and template == "formationV1.mps":  # biologic settings template and formation project
            protocol = Settings.from_file(os.path.join(BIOLOGIC_TEMPLATE_DIR, template))
            protocol = protocol.formation_protocol_bcs(protocol_params)
            filename = "{}.mps".format(filename_prefix)
            filename = os.path.join(output_directory, "settings", filename)
        elif ".sdu" in template:  # No schedule file templates implemented
            failure = {
                "comment": "Schedule file generation is not yet implemented",
                "error": "Not Implemented"
            }
            file_generation_failures.append(failure)
            logger.warning("Schedule file generation not yet implemented", extra=s)
            result = "error"
            continue
        else:  # Unable to match to any known template format
            failure = {
                "comment": "Unable to find template: " + template,
                "error": "Not Found",
            }
            file_generation_failures.append(failure)
            warnings.warn("Unsupported file template {}, skipping.".format(template))
            result = "error"
            continue

        logger.info(filename, extra=s)
        protocol.to_file(filename)
        successfully_generated_files.append(filename)
        names.append(filename_prefix + "_")

    # This block of code produces the file containing all of the run file
    # names produced in this function call. This is to make starting tests easier
    _, namefile = os.path.split(csv_filename)
    namefile = namefile.split("_")[0] + "_names_"
    namefile = namefile + datetime.datetime.now().strftime("%Y%m%d_%H%M") + ".csv"

    names_dir = os.path.join(output_directory, "names")
    os.makedirs(names_dir, exist_ok=True)

    with open(os.path.join(names_dir, namefile), "w", newline="") as outputfile:
        wr = csv.writer(outputfile)
        for name in names:
            wr.writerow([name])
    outputfile.close()

    num_generated_files = len(successfully_generated_files)
    num_generation_failures = len(file_generation_failures)
    num_files = num_generated_files + num_generation_failures

    message = {
        "comment": "Generated {} of {} protocols".format(num_generated_files, num_files),
        "error": ""
    }
    if not result:
        result = "success"
    else:
        message["error"] = "Failed to generate {} of {} protocols".format(num_generation_failures, num_files)
        logger.error(message["error"])

    return successfully_generated_files, file_generation_failures, result, message