Esempio n. 1
0
def SimplifiedBarChart(dfs,
                       measurement,
                       configs,
                       analysisType,
                       xaxis,
                       bins=50,
                       **addConfigs):
    """Generates a simplified bar chart with a simplified x axis, can be handy if you have lots of points """
    newConfigs = addConfigs
    log.info("Generating BarChart for measurement {}...".format(measurement))
    finalplots = None
    try:
        for key in dfs["keys"]:
            log.info("Generating histograms for measurement {} for file {}...".
                     format(measurement, key))
            # Sanatize data
            data = dfs[key]["data"][[measurement,
                                     xaxis]].dropna()  # Drop all nan
            invertedaxis = data.reset_index().set_index(measurement)
            data = np.histogram(data[measurement], bins=data[xaxis])

            plt = hv.Histogram(data,
                               label="BarChart: {}".format(measurement),
                               group="{}".format(key))

            try:
                xlabel = "{} [{}]".format(
                    measurement,
                    dfs[dfs["keys"][0]]["units"][dfs[
                        dfs["keys"][0]]["measurements"].index(measurement)],
                )
            except Exception as err:
                log.error(
                    "Label could not be generated for Histogram {}. Error: {}".
                    format(measurement, err))
                xlabel = "X-Axis"

            plt.opts(xlabel=xlabel)
            # Update the plot specific options if need be
            generalOptions = configs[analysisType].get("General", {})
            newConfigs.update(generalOptions.copy())
            data_options = (configs[analysisType].get(measurement, {}).get(
                "Single Histogram", {}).get("PlotOptions", {}))
            newConfigs.update(configs[analysisType].get(
                "{}Options".format("Histogram"), {}))
            newConfigs.update(data_options)
            plots = customize_plot(plt, "", configs[analysisType],
                                   **newConfigs)

            if finalplots:
                finalplots += plots
            else:
                finalplots = plots
    except Exception as err:
        log.error(
            "Unexpected error happened during Hist plot generation {}. Error: {}"
            .format(measurement, err))
        return None

    return finalplots
Esempio n. 2
0
def BoxWhisker(dfs, measurement, configs, analysisType, **addConfigs):
    """Plots a measurement from all df as boxwisker"""
    newConfigs = addConfigs
    log.info("Generating BoxWhisker Plot for {}".format(measurement))
    try:
        plot = hv.BoxWhisker(
            dfs["All"],
            kdims="Name",
            vdims=measurement,
            label="BoxWhisker: {}".format(measurement),
            group="BoxWhisker: {}".format(measurement),
        )
        # plot = relabelPlot(plot, label="{}".format(measurement))
        # get labels from the configs
        # ylabel = "{} [{}]".format(measurement, dfs[dfs["keys"][0]]["units"][dfs[dfs["keys"][0]]["measurements"].index(measurement)])
        try:
            ylabel = "{} [{}]".format(
                measurement,
                dfs[dfs["keys"][0]]["units"][dfs[
                    dfs["keys"][0]]["measurements"].index(measurement)],
            )
        except Exception as err:
            log.error(
                "Label could not be genereated for concatonated Histogram {}. Error: {}"
                .format(measurement, err))
            ylabel = "X-Axis"
        plot.opts(
            box_alpha=0.3,
            xrotation=80,
            box_color="blue",
            height=500,
            show_legend=False,
            width=600,
            whisker_color="blue",
            ylabel=ylabel,
        )

        # Update the plot specific options if need be
        generalOptions = configs[analysisType].get("General", {})
        newConfigs.update(generalOptions.copy())
        data_options = (configs[analysisType].get(measurement, {}).get(
            "BoxWhisker", {}).get("PlotOptions", {}))
        newConfigs.update(configs[analysisType].get(
            "{}Options".format("BoxWhisker"), {}))
        newConfigs.update(data_options)
        plot = customize_plot(plot, "", configs[analysisType], **newConfigs)

    except Exception as err:
        log.error(
            "Unexpected error happened during BoxWhisker plot generation {}. Error: {}"
            .format(measurement, err))
        return None

    return plot
Esempio n. 3
0
    def do_CCE(self):
        """Runs the CCE calculations and does the plot for the CCE measurement for ION and LASER sources"""
        if not "IonPad1" in self.measurements: # Todo: find a better check
            return

        from scipy import integrate
        IntPad1 = self.data["All"].groupby(self.data["All"].Name).apply(lambda g: integrate.trapz(g.IonPad1_1, x=g.IonPad1))
        IntPad2 = self.data["All"].groupby(self.data["All"].Name).apply(lambda g: integrate.trapz(g.IonPad2_1, x=g.IonPad2))
        TotalElectrons = ((IntPad1+IntPad2)/1.602e-19)
        Electronsperum = ((IntPad1+IntPad2)/1.602e-19)/self.config["TCAD"].get("CCE",{}).get("BulkThickness", 1)
        picoCoulombs = ((IntPad1 + IntPad2) * 1e12)
        units = {"Total electrons": TotalElectrons, "Electrons per um": Electronsperum, "Pico Coulombs": picoCoulombs}

        self.log.info("TotalElectrons: {} \n"
                      "Electrons per um: {}\n"
                      "picoCoulombs: {} \n".format(TotalElectrons, Electronsperum, picoCoulombs))

        CCEOptions = self.config["TCAD"].get("CCE",{}).get("General", {})
        CCEOptions.update(self.config["TCAD"].get("CCE",{}).get("PlotOptions", {}))

        for pltType in self.config["TCAD"].get("CCE",{}).get("PlotStyles", ["Bars"]):
            plot = plainPlot(pltType,
                      self.config["TCAD"].get("CCE", {})["FileXPositions"],
                      units[self.config["TCAD"].get("CCE",{}).get("yAxisUnits", "Pico Coulombs")],
                      self.config["TCAD"].get("CCE",{}).get("PlotLabel", "NOName"),
                      "CCE",
                      self.config["TCAD"]
                      )

            if self.PlotDict["All"]:
                self.PlotDict["All"] += plot
            else:
                self.PlotDict["All"] = plot

        # Generate all Plots from the individual Files
        for pltType in self.config["TCAD"].get("IonSource",{}).get("PlotStyles", ["Curve"]):
            for file in self.data["keys"]:
                PlotPad1 = plainPlot(pltType, self.data[file]["data"].IonPad1,self.data[file]["data"].IonPad1_1, label="Pad1", plotName="IonSource", configs=self.config["TCAD"])
                PlotPad2 = plainPlot(pltType, self.data[file]["data"].IonPad2,self.data[file]["data"].IonPad2_1, label="Pad2", plotName="IonSource", configs=self.config["TCAD"])
                PLOT = PlotPad1*PlotPad2
                PLOT = customize_plot(PLOT, "IonSource", self.config["TCAD"])

                self.PlotDict["All"] += PLOT
Esempio n. 4
0
def Histogram(dfs,
              measurement,
              configs,
              analysisType,
              bins=50,
              iqr=None,
              **addConfigs):
    """Generates a Points Plot with a corresponding Histogram"""
    newConfigs = addConfigs
    log.info("Generating histograms for measurement {}...".format(measurement))
    finalplots = None
    try:
        for key in dfs["keys"]:
            log.info("Generating histograms for measurement {} for file {}...".
                     format(measurement, key))
            # Sanatize data
            data = dfs[key]["data"][measurement].dropna()  # Drop all nan
            if iqr:
                log.info("Outliers correction with iqr: {}".format(iqr))
                data = reject_outliers(data, iqr)
            mean = np.round(np.mean(data), 2)
            rms = np.round(np.sqrt(np.mean(data**2)), 2)
            std = np.round(np.std(data), 2)
            median = np.round(np.median(data), 2)
            data = np.histogram(data, bins=bins)
            plt = hv.Histogram(data,
                               label="Histogram: {}".format(measurement),
                               group="Histogram: {}: {}".format(
                                   measurement, key))

            try:
                xlabel = "{} [{}]".format(
                    measurement, dfs[dfs["keys"][0]]["units"][dfs[
                        dfs["keys"][0]]["measurements"].index(measurement)])
            except Exception as err:
                log.error(
                    "Label could not be generated for Histogram {}. Error: {}".
                    format(measurement, err))
                xlabel = "X-Axis"

            plt.opts(xlabel=xlabel)
            # Update the plot specific options if need be
            generalOptions = configs[analysisType].get("General", {})
            newConfigs.update(generalOptions.copy())
            data_options = configs[analysisType].get(measurement, {}).get(
                "Single Histogram", {}).get("PlotOptions", {})
            newConfigs.update(configs[analysisType].get(
                "{}Options".format("Histogram"), {}))
            newConfigs.update(data_options)
            plots = customize_plot(plt, "", configs[analysisType],
                                   **newConfigs)

            # Add text
            text = '\nMean: {mean} \n' \
                   'Median: {median} \n' \
                   'RMS: {rms}\n' \
                   'std: {std}'.format(mean=mean,
                                       median=median,
                                       rms=rms,
                                       std=std)
            log.info(text)
            y = data[0].max()
            x = data[1][int(len(data[1]) * 0.9)]
            text = hv.Text(x, y, text).opts(fontsize=30)
            #text = text_box(text, x, y, boxsize= (100, 150))
            plots = plots * text

            if finalplots:
                finalplots += plots
            else:
                finalplots = plots
    except Exception as err:
        log.error(
            "Unexpected error happened during Hist plot generation {}. Error: {}"
            .format(measurement, err))
        return None

    return finalplots
Esempio n. 5
0
def concatHistogram(dfs,
                    measurement,
                    configs,
                    analysisType,
                    bins=50,
                    iqr=None,
                    **addConfigs):
    """Concatenates dataframes and generates a Histogram for all passed columns"""
    newConfigs = addConfigs
    log.info("Generating concat histograms for measurements {}...".format(
        measurement))
    try:
        df = dfs["All"]
        # Sanatize data
        data = df[measurement].dropna()  # Drop all nan
        if iqr:
            log.info("Outliers correction with iqr: {}".format(iqr))
            data = reject_outliers(data, iqr)
        mean = np.round(np.mean(data), 2)
        rms = np.round(np.sqrt(np.mean(data**2)), 2)
        std = np.round(np.std(data), 2)
        median = np.round(np.median(data), 2)
        data = np.histogram(data, bins=bins)

        plt = hv.Histogram(
            data,
            label="Concatenated Histogram: {}".format(measurement),
            group="Concatenated Histogram: {}".format(measurement))
        #plt = hv.Histogram(data, vdims=to_plot, group="Concatenated Histogram: {}".format(to_plot))

        try:
            xlabel = "{} [{}]".format(
                measurement, dfs[dfs["keys"][0]]["units"][dfs[
                    dfs["keys"][0]]["measurements"].index(measurement)])
        except Exception as err:
            log.error(
                "Label could not be genereated for concatonated Histogram {}. Error: {}"
                .format(measurement, err))
            xlabel = "X-Axis"

        plt.opts(xlabel=xlabel)
        # Update the plot specific options if need be
        generalOptions = configs[analysisType].get("General", {})
        newConfigs.update(generalOptions.copy())
        data_options = configs[analysisType].get(measurement, {}).get(
            "Concatenated Histogram", {}).get("PlotOptions", {})
        newConfigs.update(configs[analysisType].get(
            "{}Options".format("Histogram"), {}))
        newConfigs.update(data_options)
        #addConfigs.update({"xlabel": measurement})
        plots = customize_plot(plt, "", configs[analysisType], **newConfigs)

        # Add text
        text = '\nMean: {mean} \n' \
               'Median: {median} \n' \
               'RMS: {rms}\n' \
               'std: {std}'.format(mean=mean,
                                median=median,
                                rms=rms,
                                std=std)
        log.info(text)
        y = data[0].max()
        x = data[1][int(len(data[1]) * 0.9)]
        text = hv.Text(x, y, text).opts(fontsize=30)
        plots = plots * text

    except Exception as err:
        log.error(
            "Unexpected error happened during concatHist plot generation {}. Error: {}"
            .format(measurement, err))
        return None

    return plots
Esempio n. 6
0
    def find_flatBand_voltage(
        self,
        plot,
        data,
        configs,
        indexMax,
        indexMin,
        df,
        cv_files,
        voltage_value_of_max_firstder,
        **addConfigs
    ):  # cv is the list containing all the cvmos files
        """
        Finds the full depletion voltage of all data samples and adds a vertical line for the full depletion in the
        plot. Vertical line is the mean of all measurements. Furthermore, adds a text with the statistics.
        :param plot: The plot object
        :param data: The data files
        :param configs: the configs
        :param **addConfigs: the configs special for the 1/C2 plot, it is recommended to pass the same options here again, like in the original plot!
        :return: The updated plot
        """
        # global Right_stats, fit_stats
        self.log.info("Searching for flat band voltage in all files...")
        sample = deepcopy(data[df])

        # Create a new data frame with just two columns
        try:
            df1 = pd.DataFrame(
                {
                    "xaxis": sample["data"]["voltage"],
                    "yaxis": sample["data"]["CapacityCopy"],
                }
            )
        except Exception:
            df1 = pd.DataFrame(
                {
                    "xaxis": sample["data"]["Voltage"],
                    "yaxis": sample["data"]["CapacityCopy"],
                }
            )
        df1 = df1.dropna()

        # Loop one time from the right side, to get the slope of the accumulation region, and then loop on the fit region to get the fit slope
        RR2 = 0
        fitR2 = 0
        for idx in range(5, len(df1) - 5):
            # Right
            slope_right, intercept_right, r_right, p_value, std_err_right = linregress(
                df1["xaxis"][idx:], df1["yaxis"][idx:]
            )
            r2_right = r_right * r_right
            self.log.debug(
                "Right side fit: Slope {}, intercept: {}, r^2: {}, std: {}".format(
                    slope_right, intercept_right, r2_right, std_err_right
                )
            )

            # See if the r2 value has increased and store it
            if r2_right >= RR2:
                RR2 = r2_right
                RightEndPoints = (
                    (
                        df1["xaxis"][idx],
                        slope_right * df1["xaxis"][idx] + intercept_right,
                    ),
                    (
                        df1["xaxis"][len(df1["xaxis"]) - 1],
                        slope_right * df1["xaxis"][len(df1["xaxis"]) - 1]
                        + intercept_right,
                    ),
                )
                Right_stats = [
                    RightEndPoints,
                    slope_right,
                    intercept_right,
                    r_right,
                    p_value,
                    std_err_right,
                ]

        # Fit central region
        for idx in range(indexMax, indexMin - 1):
            # Do central fit
            slope_fit, intercept_fit, r_fit, p_valuefit, std_err_fit = linregress(
                df1["xaxis"][idx : indexMin - 1], df1["yaxis"][idx : indexMin - 1]
            )
            r2_fit = r_fit * r_fit
            self.log.debug(
                "central fit: Slope {}, intercept: {}, r^2: {}, std: {}".format(
                    slope_fit, intercept_fit, r2_fit, std_err_fit
                )
            )

            # See if the r2 value has increased and store it
            if r2_fit >= fitR2:
                fitR2 = r2_fit
                fitEndPoints = (
                    (
                        df1["xaxis"][indexMax],
                        slope_fit * df1["xaxis"][indexMax] + intercept_fit,
                    ),
                    (
                        df1["xaxis"][idx + 1],
                        slope_fit * df1["xaxis"][idx + 1] + intercept_fit,
                    ),  # use idx +1 to avoid having the same end points
                )
                fit_stats = [
                    fitEndPoints,
                    slope_fit,
                    intercept_fit,
                    r_fit,
                    p_valuefit,
                    std_err_fit,
                ]

        # Add central slope
        xmax = df1["xaxis"][indexMin]
        fit_line = np.array(
            [
                [
                    df1["xaxis"][indexMax - 3],
                    fit_stats[1] * df1["xaxis"][indexMax - 3] + fit_stats[2],
                ],
                [xmax + 0.2, fit_stats[1] * (xmax + 0.2) + fit_stats[2]],
            ]
        )

        # Add right slope
        xmax = df1["xaxis"][len(df1["yaxis"]) - 1]
        right_line = np.array(
            [
                [
                    df1["xaxis"][indexMax - 3],
                    Right_stats[1] * df1["xaxis"][indexMax - 3] + Right_stats[2],
                ],
                [xmax, Right_stats[1] * xmax + Right_stats[2]],
            ]
        )

        # Compute the flatband voltage
        flatband_voltage = line_intersection(fit_stats[0], Right_stats[0])
        self.log.info(
            "Flatband voltage to data file {} is {}".format(df, flatband_voltage[0])
        )

        # Find oxide thickness Tox in nm
        Accum_capacitance = np.max(df1["yaxis"]) * (
            float(self.data[df]["header"][0].split(":")[1]) * (1e-8)
        )  # float(..) is the area.
        Accum_capacitance_table = "{:.2e}".format(Accum_capacitance)
        Accum_capacitance_normalized = np.max(df1["yaxis"])  # F/cm^2
        Accum_capacitance_normalized_table = "{:.2e}".format(
            Accum_capacitance_normalized
        )
        Tox = (
            self.config["IV_PQC_parameter"]["epsilonNull"]
            * self.config["IV_PQC_parameter"]["epsilonSiliconOxide"]
            * 1e5
            / Accum_capacitance_normalized
        )
        Tox_table = "{:.2e}".format(Tox)

        # Find Fixed oxide charge Nox in cm^-2
        phi_s = (
            self.config["IV_PQC_parameter"]["electronAffinity"]
            + self.config["IV_PQC_parameter"]["bandGapEnergy"] / 2
            + (
                self.config["IV_PQC_parameter"]["boltzmannConstant"]
                * self.config["IV_PQC_parameter"]["Temperature"]
                * np.log(
                    self.config["IV_PQC_parameter"]["SiliconDoping"]
                    / self.config["IV_PQC_parameter"]["intrinsicDopingConcentration"]
                )
            )
            / self.config["IV_PQC_parameter"]["q"]
        )
        phi_ms = self.config["IV_PQC_parameter"]["phi_m"] - phi_s
        Nox = (Accum_capacitance_normalized * (phi_ms + flatband_voltage[0])) / (
            self.config["IV_PQC_parameter"]["q"]
        )
        Nox_table = "{:.2e}".format(
            Nox
        )  # Value to insert later on in the results table

        # Append the values resulting from the analysis to the corresponding lists.
        fbvoltage.append(flatband_voltage[0])
        Accum_capacitance_list.append(Accum_capacitance_table)
        Accum_capacitance_normalized_list.append(Accum_capacitance_normalized_table)
        Tox_list.append(Tox_table)
        Nox_list.append(Nox_table)

        # Add text
        text = hv.Text(
            10,
            0.00000000065,
            "Flat band voltage_fit_2nd derivative: {} V \n"
            "Flat band voltage first derivative: {} V \n"
            "C accumulation: {} F \n"
            "C accumulation/A: {} F/cm\N{SUPERSCRIPT TWO} \n"
            "Tox: {} nm \n"
            "Nox: {} cm\N{SUPERSCRIPT MINUS}\N{SUPERSCRIPT TWO}".format(
                np.round(np.median(flatband_voltage[0]), 2),
                np.round(voltage_value_of_max_firstder, 2),
                np.round(Accum_capacitance, 10),
                np.round(Accum_capacitance_normalized, 10),
                np.round(Tox, 2),
                np.format_float_scientific(Nox, 2),
            ),
        ).opts(style=dict(text_font_size="25pt"))

        # If more than one file do not do the derivates plots
        if not len(cv_files) == 1:
            returnPlot = plot
            returnPlot = customize_plot(
                returnPlot, "1C2", configs["IV_PQC"], **addConfigs
            )
            return (
                returnPlot,
                flatband_voltage[0],
                Accum_capacitance_table,
                Accum_capacitance_normalized_table,
                Tox_table,
                Nox_table,
            )

        elif len(cv_files) == 1:
            # Plot a vertical line in the value of the fb voltage
            vline = hv.VLine(flatband_voltage[0]).opts(color="black", line_width=1.0)

            # Plots of the derivatives
            secondDerivativePlot = self.basePlots5.Curve.secondderivative

            # Plots of the fits
            right_line = hv.Curve(right_line).opts(color="blue", line_width=1.0)
            fit_line = hv.Curve(fit_line).opts(color="red", line_width=1.5)
            returnPlot = plot * right_line * fit_line * secondDerivativePlot * vline
            returnPlot = customize_plot(
                returnPlot, "1C2", configs["IV_PQC"], **addConfigs
            )
            returnplot2 = plot * fit_line * right_line * vline * text
            return (
                returnPlot,
                flatband_voltage[0],
                Accum_capacitance_table,
                Accum_capacitance_normalized_table,
                Tox_table,
                Nox_table,
                returnplot2,
            )
Esempio n. 7
0
    def add_single_plots(self, xaxis, yaxis, name):
        points_plot = (xaxis, yaxis)
        interp_plot = hv.Curve(points_plot)
        interp_plot = customize_plot(interp_plot, name, self.config["IV_PQC"])

        return interp_plot
Esempio n. 8
0
    def find_full_depletion_c2(self, plot, data, configs, diode_files, **addConfigs):
        """
        Finds the full depletion voltage of all data samples and adds a vertical line for the full depletion in the
        plot. Vertical line is the mean of all measurements. Furthermore, adds a text with the statistics.
        :param plot: The plot object
        :param data: The data files
        :param configs: the configs
        :param **addConfigs: the configs special for the 1/C2 plot, it is recomended to pass the same options here again, like in the original plot!
        :return: The updated plot
        """
        # global LeftEndPoints, df
        Left_stats = np.zeros((len(diode_files), 6), dtype=np.object)
        self.log.info("Searching for full depletion voltage in all files...")

        for samplekey in diode_files:
            if "1C2" not in data[samplekey]["data"]:
                self.log.warning(
                    "Full depletion calculation could not be done for data set: {}".format(
                        samplekey
                    )
                )
            else:
                self.log.debug("Data: {}".format(samplekey))
                sample = deepcopy(data[samplekey])
                df = pd.DataFrame(
                    {"xaxis": sample["data"]["Voltage"], "yaxis": sample["data"]["1C2"]}
                )
                df = df.dropna()

                # Loop one time from the from the left side, to get the slope
                LR2 = 0
                for idx in range(5, len(df) - 20):
                    # Left
                    (
                        slope_left,
                        intercept_left,
                        r_left,
                        p_value,
                        std_err_left,
                    ) = linregress(df["xaxis"][:-idx], df["yaxis"][:-idx])
                    r2_left = r_left * r_left
                    self.log.debug(
                        "Left side fit: Slope {}, intercept: {}, r^2: {}, std: {}".format(
                            slope_left, intercept_left, r2_left, std_err_left
                        )
                    )

                    # See if the r2 value has increased and store end points
                    if r2_left >= LR2:
                        LR2 = r2_left
                        LeftEndPoints = (
                            (df["xaxis"][0], intercept_left),
                            (
                                df["xaxis"][idx],
                                slope_left * df["xaxis"][idx] + intercept_left,
                            ),
                        )

        # Find the right fit by averaging on the final 20 points
        average_right = np.mean(list(df["yaxis"][-20:]))
        RightEndPoints = [
            (df["xaxis"][len(df["xaxis"]) - 20], average_right),
            (df["xaxis"][len(df["xaxis"]) - 1], average_right),
        ]

        # Find the line intersection
        full_depletion_voltages = line_intersection(LeftEndPoints, RightEndPoints)
        fdepvoltage.append(full_depletion_voltages[0])
        self.log.info(
            "Full depletion voltage: {} V".format(
                np.round(full_depletion_voltages[0], 2)
            )
        )

        # Add vertical line for full depletion
        vline = hv.VLine(full_depletion_voltages[0]).opts(color="black", line_width=5.0)

        # Add slopes
        left_line = np.array(
            [
                [0, np.median(Left_stats[:, 2])],
                [full_depletion_voltages[0], full_depletion_voltages[1]],
            ]
        )
        left_line = hv.Curve(left_line).opts(color="grey")
        right_line = hv.HLine(average_right).opts(color="grey")

        # Add text
        text = hv.Text(
            230,
            5e21,
            "Depletion voltage: {} V".format(np.round(full_depletion_voltages[0], 2)),
        ).opts(style=dict(text_font_size="20pt"))

        # Update the plot specific options if need be
        returnPlot = plot * vline * right_line * left_line * text
        returnPlot = customize_plot(returnPlot, "1C2", configs["IV_PQC"], **addConfigs)

        return returnPlot, full_depletion_voltages[0]
Esempio n. 9
0
    def run(self):
        """Runs the script"""

        # Add the measurement to the list
        # Plot all IV measurements
        # (data, config, xaxis_measurement, analysis_name, do_not_plot=(), plot_only=(), keys=None, **kwargs)
        IVplot = None
        IVSubplot = None
        self.PlotDict["All"] = None
        for file in self.data["keys"]:
            if "IV" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "IV"] = self.config[
                        self.analysisName]["current"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas,
                    )
                    tempplot = customize_plot(tempplot, "current",
                                              self.config[self.analysisName])
                    if IVplot:
                        IVplot *= tempplot
                    else:
                        IVplot = tempplot

                    if IVSubplot:
                        IVSubplot += tempplot
                    else:
                        IVSubplot = tempplot
        IVplot = customize_plot(IVplot, "current",
                                self.config[self.analysisName])

        # Plot all CV measurements
        # (data, config, xaxis_measurement, analysis_name, do_not_plot=(), plot_only=(), keys=None, **kwargs)
        CVplot = None
        for file in self.data["keys"]:
            if "CV" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "CV"] = self.config[
                        self.analysisName]["capacitance"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas + "CV",
                    )
                    if CVplot:
                        CVplot *= tempplot
                    else:
                        CVplot = tempplot
        CVplot = customize_plot(CVplot, "capacitance",
                                self.config[self.analysisName])

        # Add full depletion point to 1/c^2 curve
        c2plot = None
        for file in self.data["keys"]:
            if "1C2" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "1c2"] = self.config[
                        self.analysisName]["1C2"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas + "1c2",
                    )
                    if c2plot:
                        c2plot *= tempplot
                    else:
                        c2plot = tempplot
        c2plot = customize_plot(c2plot, "1C2", self.config[self.analysisName])

        if IVplot:
            self.PlotDict["All"] = IVplot
            self.PlotDict["All"] += IVSubplot
        if CVplot and self.PlotDict["All"]:
            self.PlotDict["All"] += CVplot + c2plot
        elif CVplot and not self.PlotDict["All"]:
            self.PlotDict["All"] = CVplot + c2plot

        # Reconfig the plots to be sure
        self.PlotDict["All"] = config_layout(
            self.PlotDict["All"],
            **self.config[self.analysisName].get("Layout", {}))
        return self.PlotDict
Esempio n. 10
0
    def find_full_depletion(self, plot, data, configs, **addConfigs):
        """
        Finds the full depletion voltage of all data samples and adds a vertical line for the full depletion in the
        plot. Vertical line is the mean of all measurements. Furthermore, adds a text with the statistics.
        :param plot: The plot object
        :param data: The data files
        :param configs: the configs
        :param **addConfigs: the configs special for the 1/C2 plot, it is recomended to pass the same options here again, like in the original plot!
        :return: The updated plot
        """

        full_depletion_voltages = np.zeros((len(data["keys"]), 2))
        Left_stats = np.zeros((len(data["keys"]), 6), dtype=np.object)
        Right_stats = np.zeros((len(data["keys"]), 6), dtype=np.object)
        self.log.info("Searching for full depletion voltage in all files...")

        for i, samplekey in enumerate(data["keys"]):
            if "1C2" not in data[samplekey]["data"]:
                self.log.warning(
                    "Full depletion calculation could not be done for data set: {}"
                    .format(samplekey))

            else:
                self.log.debug("Data: {}".format(samplekey))
                sample = deepcopy(data[samplekey])
                try:
                    df = sample["data"][["voltage",
                                         "1C2"]].rename(columns={
                                             "voltage": "xaxis",
                                             "1C2": "yaxis"
                                         })
                except:
                    df = sample["data"][["Voltage",
                                         "1C2"]].rename(columns={
                                             "Voltage": "xaxis",
                                             "1C2": "yaxis"
                                         })
                df = df.dropna()

                # Loop one time from the right side and from the left, to get both slopes
                LR2, Left_stats[i], RR2, Right_stats[
                    i] = self.calculate_slopes(df, minSize=5, startidx=5)

                # Make the line intersection
                full_depletion_voltages[i] = line_intersection(
                    Left_stats[i][0], Right_stats[i][0])
                self.log.info(
                    "Full depletion voltage to data file {} is {}, with LR^2={} and RR^2={}"
                    .format(samplekey, full_depletion_voltages[i], LR2, RR2))

        # Add vertical line for full depletion
        # Calculate the mean of all full depeltion voltages and draw a line there
        valid_indz = np.nonzero(full_depletion_voltages[:, 0])
        vline = hv.VLine(
            np.mean(full_depletion_voltages[valid_indz],
                    axis=0)[0]).opts(color="black", line_width=5.0)

        # Add slopes
        xmax = df["xaxis"][len(df["yaxis"]) - 1]
        left_line = np.array([
            [0, np.median(Left_stats[:, 2])],
            [
                xmax,
                np.median(Left_stats[:, 1]) * xmax +
                np.median(Left_stats[:, 2]),
            ],
        ])
        left_line = hv.Curve(left_line).opts(color="grey")

        right_line = np.array([
            [0, np.median(Right_stats[:, 2])],
            [
                xmax,
                np.median(Right_stats[:, 1]) * xmax +
                np.median(Right_stats[:, 2]),
            ],
        ])
        right_line = hv.Curve(right_line).opts(color="grey")

        # Add text
        self.log.info(
            "Full depletion voltage: {} V, "
            "Error: {} V".format(
                np.round(np.median(full_depletion_voltages[valid_indz, 0]), 2),
                np.round(np.std(full_depletion_voltages[valid_indz, 0]), 2),
            ))
        # text = hv.Text(np.mean(full_depletion_voltages[valid_indz], axis=0)[0]*2, np.mean(full_depletion_voltages[valid_indz], axis=0)[1]*1.2, 'Depletion voltage: {} V \n'
        #                'Error: {} V'.format(np.round(np.mean(full_depletion_voltages[:, 0]), 2),
        #                                   np.round(np.std(full_depletion_voltages[valid_indz, 0]), 2))
        #               ).opts(fontsize=30)

        bounds = np.mean(full_depletion_voltages[valid_indz], axis=0)
        text = text_box(
            "Depletion voltage: {} V \n"
            "Error: {} V".format(
                np.round(np.mean(full_depletion_voltages[:, 0]), 2),
                np.round(np.std(full_depletion_voltages[valid_indz, 0]), 2),
            ),
            np.mean(full_depletion_voltages[valid_indz], axis=0)[0] * 2,
            np.mean(full_depletion_voltages[valid_indz], axis=0)[1] * 1.3,
            boxsize=(200, bounds[1] * 0.3),
        )
        # Update the plot specific options if need be
        returnPlot = vline * right_line * left_line * text * plot
        # returnPlot = relabelPlot(returnPlot, "CV CURVES - Full depletion calculation")
        returnPlot = customize_plot(returnPlot, "1C2",
                                    configs[self.analysisName], **addConfigs)

        return returnPlot
Esempio n. 11
0
    def run(self):
        """Runs the script"""

        # Add the measurement to the list
        # Plot all IV measurements
        # (data, config, xaxis_measurement, analysis_name, do_not_plot=(), plot_only=(), keys=None, **kwargs)
        IVplot = None
        self.PlotDict["All"] = None
        for file in self.data["keys"]:
            if "IV" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "IV"] = self.config[
                        self.analysisName]["current"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas + "IV",
                    )
                    if IVplot:
                        IVplot *= tempplot
                    else:
                        IVplot = tempplot
        IVplot = customize_plot(IVplot, "current",
                                self.config[self.analysisName])

        # Plot all CV measurements
        # (data, config, xaxis_measurement, analysis_name, do_not_plot=(), plot_only=(), keys=None, **kwargs)
        CVplot = None
        for file in self.data["keys"]:
            if "CV" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "CV"] = self.config[
                        self.analysisName]["capacitance"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas + "CV",
                    )
                    if CVplot:
                        CVplot *= tempplot
                    else:
                        CVplot = tempplot
        CVplot = customize_plot(CVplot, "capacitance",
                                self.config[self.analysisName])

        # Add full depletion point to 1/c^2 curve
        c2plot = None
        for file in self.data["keys"]:
            if "1C2" in file:
                for meas in self.measurements:
                    self.config[self.analysisName][meas + "1c2"] = self.config[
                        self.analysisName]["1C2"]
                    tempplot = plot(
                        self.data,
                        self.config,
                        self.xaxis,
                        self.analysisName,
                        plot_only=(meas, ),
                        keys=(file, ),
                        do_not_plot=self.donts,
                        PlotLabel=meas + "1c2",
                    )
                    if c2plot:
                        c2plot *= tempplot
                    else:
                        c2plot = tempplot
        c2plot = customize_plot(c2plot, "1C2", self.config[self.analysisName])

        # if self.config[self.analysisName].get("1C2", {}).get("DoFullDepletionCalculation", False):
        #    try:
        #        if self.basePlots.Overlay.CV_CURVES_hyphen_minus_Full_depletion.children:
        #            c2plot = self.basePlots.Overlay.CV_CURVES_hyphen_minus_Full_depletion.opts(clone = True)
        ##        else: c2plot = self.basePlots.Curve.CV_CURVES_hyphen_minus_Full_depletion.opts(clone = True)
        #        fdestimation = self.find_full_depletion(c2plot, self.data, self.config, PlotLabel="Full depletion estimation")
        #        self.PlotDict["All"] += fdestimation
        #        self.PlotDict["BasePlots"] += fdestimation
        #    except Exception as err:
        #        self.log.warning("No full depletion calculation possible... Error: {}".format(err))

        # Reconfig the plots to be sure
        # self.PlotDict["All"] = config_layout(self.PlotDict["All"], **self.config[self.analysisName].get("Layout", {}))

        self.PlotDict["All"] = IVplot + CVplot + c2plot
        # Reconfig the plots to be sure
        self.PlotDict["All"] = config_layout(
            self.PlotDict["All"],
            **self.config[self.analysisName].get("Layout", {}))
        return self.PlotDict