""" This module contains the functions called by main.
"""
from bedanalyst.config import *
[docs]def plot_funs(dc_param_range, dc_fuzzy_funs, dc_disfuzzy_funs):
"""
Function to plot the membership functions of the parameters and defuzzyfication membership functions into one plot.
Args:
dc_param_range (dict): arrays of float values of the six parameters defined into utils.generate_ranges()
dc_fuzzy_funs (dict): arrays of membership fuzzy functions values of the given ranges of the six parameters
dc_disfuzzy_funs (dict): arrays of membership defuzzy functions values of the given ranges of the six parameters
Returns:
None
"""
fig, (ax0, ax1, ax2, ax3, ax4, ax5) = plt.subplots(nrows=6, figsize=(4, 11))
# plot fuzzy functions of Fine Sediment Share
ax0.plot(dc_param_range["fs"], dc_fuzzy_funs["fs_c"], 'gray', linewidth=1.5, label='High')
ax0.plot(dc_param_range["fs"], dc_fuzzy_funs["fs_nc"], 'gray', linestyle="--", linewidth=1.5, label='Low')
ax0.set_xlabel("FSF [%]")
ax0.set_ylabel("\u03BC [-]")
ax0.legend()
ax0.set_xlim(left=0)
ax0.set_ylim(bottom=0)
ax0.legend(loc="lower right")
# plot fuzzy functions of hydraulic conductivity
ax1.plot(dc_param_range["kf"], dc_fuzzy_funs["kf_c"], 'gray', linestyle="--", linewidth=1.5, label='Low')
ax1.plot(dc_param_range["kf"], dc_fuzzy_funs["kf_nc"], 'gray', linewidth=1.5, label='High')
ax1.set_xlabel("kf [m/s]")
ax1.set_xscale("log")
ax1.set_ylabel("\u03BC [-]")
ax1.legend()
ax1.set_ylim(bottom=0)
ax1.legend(loc="lower right")
# plot fuzzy functions of porosity
ax2.plot(dc_param_range["po"] / 100, dc_fuzzy_funs["po_c"], 'gray', linestyle="--", linewidth=1.5, label='Low')
ax2.plot(dc_param_range["po"] / 100, dc_fuzzy_funs["po_nc"], 'gray', linewidth=1.5, label='High')
ax2.set_xlabel("n [-]")
ax2.set_ylabel("\u03BC [-]")
ax2.legend()
ax2.set_xlim(left=0)
ax2.set_ylim(bottom=0)
ax2.legend(loc="lower right")
# plot fuzzy functions of IDOC
ax3.plot(dc_param_range["idoc"], dc_fuzzy_funs["idoc_c"], 'gray', linestyle="--", linewidth=1.5, label='Low')
ax3.plot(dc_param_range["idoc"], dc_fuzzy_funs["idoc_nc"], 'gray', linewidth=1.5, label='High')
ax3.set_xlabel("IDOC [mg/L]")
ax3.set_ylabel("\u03BC [-]")
ax3.legend()
ax3.set_xlim(left=0)
ax3.set_ylim(bottom=0)
ax3.legend(loc="lower right")
# plot fuzzy functions of Ratio (Huston & Fox)
ax4.plot(dc_param_range["ratio"], dc_fuzzy_funs["ratio_c"], 'gray', linestyle="--", linewidth=1.5, label='Bridging')
ax4.plot(dc_param_range["ratio"], dc_fuzzy_funs["ratio_nc"], 'gray', linewidth=1.5, label='USP')
ax4.set_xlabel("Ratio (Huston & Fox) [-]")
ax4.set_ylabel("\u03BC [-]")
ax4.legend()
ax4.set_xlim(left=0)
ax4.set_ylim(bottom=0)
ax4.legend(loc="lower right")
# plot defuzzification functions of
ax5.plot(dc_param_range["doc"], dc_disfuzzy_funs["doc_lo"], 'black', linestyle="-.", linewidth=1.5, label='NC-dfz')
ax5.plot(dc_param_range["doc"], dc_disfuzzy_funs["doc_md"], 'black', linestyle="-", linewidth=1.5, label='MC-dfz')
ax5.plot(dc_param_range["doc"], dc_disfuzzy_funs["doc_hi"], 'black', linestyle="--", linewidth=1.5, label='SC-dfz')
ax5.set_xlabel("Degree of Clogging [-]")
ax5.set_ylabel("\u03BC [-]")
ax5.legend()
ax5.set_xlim(left=0, right=1)
ax5.set_ylim(bottom=0)
ax5.legend(loc="lower right")
plt.tight_layout()
#plt.savefig(fname="output/fuzzy_functions", dpi=300)
pass
[docs]def compute_bcs(dc_limits):
"""
Function to compute bs and cs constants that define the sigmoid fuzzy membership functions (y = 1 / (1. + exp[- c * (x - b)]))
Args:
dc_limits (dict): thresholds of the membership functions defined in config.py
Returns:
dc_b (dict): b values of the membership functions
dc_c (dict): c values of the membership functions
"""
parameter_order = ["fs_c", "fs_nc",
"kf_c", "kf_nc",
"po_c", "po_nc",
"idoc_c", "idoc_nc",
"ratio_c", "ratio_nc",
"df_lo", "df_hi"
]
dc_b = {}
dc_c = {}
for fun in parameter_order:
strings = list(dc_limits.keys())
substring1 = fun
substring2 = "{}_mu_{}".format(fun.split("_")[0], fun.split("_")[1])
list_l = [string for string in strings if substring1 in string]
list_mul = [string for string in strings if substring2 in string]
l = [dc_limits[x] for x in list_l]
mul = [dc_limits[x] for x in list_mul]
# compute list of bc constants
c = -(1 / (l[1] - l[0])) * np.log(((1 - mul[1]) / mul[1]) * (mul[0] / (1 - mul[0])))
b = l[0] + (1 / c) * np.log(1 / mul[0] - 1)
# append to the list of constantes
dc_b.update({"{}_b".format(fun): b})
dc_c.update({"{}_c".format(fun): c})
# print constants of membership functions
df_b = pd.DataFrame.from_dict(data=dc_b, orient="index")
df_c = pd.DataFrame.from_dict(data=dc_c, orient="index")
#df_b.to_csv("output/functions_constants/df_b.csv")
#df_c.to_csv("output/functions_constants/df_c.csv")
return dc_b, dc_c
[docs]def compute_fuzzy_functions(dc, dc_b, dc_c):
"""
Function to compute bs and cs constants that define the sigmoid fuzzy membership functions (y = 1 / (1. + exp[- c * (x - b)]))
Args:
dc_limits (dict): thresholds of the membership functions defined in config.py
dc_b (dict): b values of the membership functions
dc_c (dict): c values of the membership functions
Returns:
(dict): arrays with the membership values of the fuzzy functions
"""
fs_c = fuzz.sigmf(dc["fs"], dc_b["fs_c_b"], dc_c["fs_c_c"])
fs_nc = fuzz.sigmf(dc["fs"], dc_b["fs_nc_b"], dc_c["fs_nc_c"])
kf_c = fuzz.sigmf(dc["kf"], dc_b["kf_c_b"], dc_c["kf_c_c"])
kf_nc = fuzz.sigmf(dc["kf"], dc_b["kf_nc_b"], dc_c["kf_nc_c"])
po_c = fuzz.sigmf(dc["po"], dc_b["po_c_b"], dc_c["po_c_c"])
po_nc = fuzz.sigmf(dc["po"], dc_b["po_nc_b"], dc_c["po_nc_c"])
idoc_c = fuzz.sigmf(dc["idoc"], dc_b["idoc_c_b"], dc_c["idoc_c_c"])
idoc_nc = fuzz.sigmf(dc["idoc"], dc_b["idoc_nc_b"], dc_c["idoc_nc_c"])
ratio_c = fuzz.sigmf(dc["ratio"], dc_b["ratio_c_b"], dc_c["ratio_c_c"])
ratio_nc = fuzz.sigmf(dc["ratio"], dc_b["ratio_nc_b"], dc_c["ratio_nc_c"])
return {"fs_c": fs_c, "fs_nc": fs_nc,
"kf_c": kf_c, "kf_nc": kf_nc,
"po_c": po_c, "po_nc": po_nc,
"idoc_c": idoc_c, "idoc_nc": idoc_nc,
"ratio_c": ratio_c, "ratio_nc": ratio_nc
}
[docs]def generate_ranges():
"""
Function to define de ranges of the parameters
Args:
None
Returns:
(dict): array with the ranges of the parameters
"""
fs = np.arange(0, 26, 0.1)
kf = np.arange(0, 10 ** -1, 10 ** -4)
po = np.arange(0, 31, 0.1)
idoc = np.arange(0, 16, 0.1)
ratio = np.arange(0, 56, 0.1)
doc = np.arange(0, 1.1, 0.01)
return {"fs": fs,
"kf": kf,
"po": po,
"idoc": idoc,
"ratio": ratio,
"doc": doc
}
[docs]def compute_desfuzzy_funs(dc_param_range, dc_b, dc_c):
"""
Function to compute defuzzification membership functions. The functions for high and low degree of clogging are
Sigmoids and for medium degree of clogging is Gaussian.
Args:
dc_param_range: arrays of float values of the six parameters defined into utils.generate_ranges()
Returns:
(dict): arrays with the membership values of the defuzzification functions
"""
doc_lo = fuzz.sigmf(dc_param_range["doc"], dc_b["df_lo_b"], dc_c["df_lo_c"])
doc_md = fuzz.gaussmf(dc_param_range["doc"], 0.5, 0.083)
doc_hi = fuzz.sigmf(dc_param_range["doc"], dc_b["df_hi_b"], dc_c["df_hi_c"])
return {"doc_lo": doc_lo,
"doc_md": doc_md,
"doc_hi": doc_hi
}
[docs]def activate_fuzzy_funs(probe, dc_param_range, dc_fuzzy_funs):
"""
Function to compute the membership values of the fuzzy functions for the parameters of a real sample.
Args:
probe (tuple): float values of the parameters of a sample in the following order (F.S, kf, n, IDOC, ratio)
dc_param_range (dict): arrays of float values of the six parameters defined into utils.generate_ranges()
dc_fuzzy_funs (dict): arrays with the membership values of the fuzzy functions
Returns:
dc_fuzzy_activated (dict): fuzzy membership float values corresponding to the parameter values of the real sample
"""
parameters = ["fs", "kf", "po", "idoc", "ratio"]
dc_fuzzy_activated = {}
for k, par in enumerate(parameters):
# define what is low or high
if par == "fs":
low = "nc"
high = "c"
else:
low = "c"
high = "nc"
# Activate membership with values of the probe
low_level = fuzz.interp_membership(dc_param_range[par],
dc_fuzzy_funs["{}_{}".format(par, low)],
probe[k])
high_level = fuzz.interp_membership(dc_param_range[par],
dc_fuzzy_funs["{}_{}".format(par, high)],
probe[k])
dc_fuzzy_activated.update({"{}_{}_low".format(par, low): low_level,
"{}_{}_high".format(par, high): high_level})
return dc_fuzzy_activated
[docs]def plot_aggregation(dc_param_range, dc_mu_desfuzzy, dc_desfuzzy_funs, activation
, degree_of_clogging, aggregated, step):
"""
Function to compute the membership values of the fuzzy functions for the parameters of a real sample.
Args:
dc_param_range (dict): arrays of float values of the six parameters defined into utils.generate_ranges()
dc_mu_desfuzzy (dict): defuzzified membership float values corresponding to the parameter values
of the real sample
dc_desfuzzy_funs (dict): arrays with the membership values of the defuzzification functions
activation (float): degree of clogging that equals to the center of mass of tha sum of the areas under
the activated defuzzification functions
degree_of_clogging (float): degree of clogging correct between 0 and 1 in utils.correct_degree_of_clogging()
aggregated (array): membership float values that define the summed area below the
activated defuzzification functions.
step (int): integer that represents the nth sample
Returns:
None
"""
x0 = np.zeros_like(dc_param_range["doc"])
fig, (ax0, ax1) = plt.subplots(nrows=2, figsize=(5, 5))
ax0.fill_between(dc_param_range["doc"], x0, dc_mu_desfuzzy["mu_nc"], facecolor='gray', alpha=1)
ax0.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_lo"], 'black', linewidth=1.5, linestyle='-.',
label="NC-dfz")
ax0.fill_between(dc_param_range["doc"], x0, dc_mu_desfuzzy["mu_mc"], facecolor='gainsboro', alpha=0.7)
ax0.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_md"], 'black', linewidth=1.5, linestyle='-', label="MC-dfz")
ax0.fill_between(dc_param_range["doc"], x0, dc_mu_desfuzzy["mu_sc"], facecolor='black', alpha=0.7)
ax0.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_hi"], 'black', linewidth=1.5, linestyle='--', label="SC-dfz")
ax0.set_xlabel("Degree of Clogging [-]")
ax0.set_ylabel("\u03BC [-]")
ax0.set_xlim(left=0, right=1)
ax0.set_ylim(bottom=0)
ax0.legend(loc="lower right")
# fill aggregated functions
ax1.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_lo"], 'black', linewidth=1.5, linestyle='-.',
label="NC-dfz")
ax1.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_md"], 'black', linewidth=1.5, linestyle='-', label="MC-dfz")
ax1.plot(dc_param_range["doc"], dc_desfuzzy_funs["doc_hi"], 'black', linewidth=1.5, linestyle='--', label="SC-dfz")
ax1.fill_between(dc_param_range["doc"], x0, aggregated, facecolor='gray', alpha=0.8)
ax1.plot([degree_of_clogging, degree_of_clogging], [0, 0.7 * activation], 'k', linewidth=1.5, alpha=0.9)
ax1.set_xlabel("Aggregated membership and result (line)")
ax1.set_ylabel("\u03BC [-]")
ax1.set_xlim(left=0, right=1)
ax1.set_ylim(bottom=0)
ax1.legend(loc="lower right")
# Turn off top/right axes
for ax in (ax0, ax1):
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()
plt.tight_layout()
#plt.savefig(fname="output/aggregation/sample_{}".format(step + 1), dpi=300)
pass
[docs]def apply_fuzzy_rules(dc_af=None, dc_desfuzzy_funs=None, centroid=False, mu_list=None):
"""
Function to choose membership value of defuzzification functions based on the fuzzy rules.
Args:
dc_af (dict): membership values of fuzzy functions of a sample
dc_desfuzzy_funs (dict): arrays with the membership values of the defuzzification functions
centroid (boolean): True to correct the limits of degree of clogging to [0,1]
mu_list (list): corrected membership function values of the activated defuzzification functions
Returns:
dc_mu_defuzzy (dict): array of membership values that define area under the curve of the defuzzification
functions
dc_mu_defuzzy_values (dict): three float values of the sample-activated defuzzification functions
"""
if centroid:
mu_sc_value = mu_list[2]
mu_mc_value = mu_list[1]
mu_nc_value = mu_list[0]
else:
mu_sc_value = max([np.fmin(dc_af["kf_c_low"], dc_af["fs_c_high"]),
np.fmin(dc_af["po_c_low"], dc_af["fs_c_high"]),
np.fmin(dc_af["kf_c_low"], dc_af["ratio_c_low"])]
)
mu_mc_value = max([np.fmin(dc_af["kf_c_low"], dc_af["idoc_nc_high"]),
np.fmin(dc_af["fs_c_high"], (1 - dc_af["kf_c_low"]))]
)
mu_nc_value = max([np.fmin(dc_af["idoc_nc_high"], dc_af["kf_nc_high"]),
np.fmin(dc_af["kf_nc_high"], dc_af["fs_nc_low"]),
np.fmin(dc_af["ratio_nc_high"], dc_af["kf_nc_high"])]
)
# class moderate clogging
mu_mc = np.fmin(mu_mc_value,
dc_desfuzzy_funs["doc_md"]
)
# class strong clogging
mu_sc = np.fmin(mu_sc_value,
dc_desfuzzy_funs["doc_hi"]
)
# class no clogging
mu_nc = np.fmin(mu_nc_value,
dc_desfuzzy_funs["doc_lo"]
)
# dict with memberships of defuzzified functions
dc_mu_defuzzy = {"mu_sc": mu_sc,
"mu_mc": mu_mc,
"mu_nc": mu_nc,
}
dc_mu_defuzzy_values = {"mu_sc": mu_sc_value,
"mu_mc": mu_mc_value,
"mu_nc": mu_nc_value, }
return dc_mu_defuzzy, dc_mu_defuzzy_values
[docs]def find_centroids(dc_desfuzzy_funs, dc_param_range):
"""
Function to find centroids of the non clogging and strong clogging defuzzification functions
Args:
dc_param_range (dict): arrays of float values of the six parameters defined into utils.generate_ranges()
dc_desfuzzy_funs (dict): arrays with the membership values of the defuzzification functions
Returns:
dc_defuzzy_centroids (dict): two float values that represent the centroids of sc and nc defuzzi-functions
"""
mu_list_nc = [0.99, 0.01, 0.01]
mu_list_sc = [0.01, 0.01, 0.99]
mu_lists = [mu_list_nc, mu_list_sc]
dic_defuzzy_centroids = {}
for k, mu_list in enumerate(mu_lists):
dc_mu_desfuzzy, _ = apply_fuzzy_rules(None, dc_desfuzzy_funs,
True, mu_list)
aggregated = np.fmax(dc_mu_desfuzzy["mu_sc"],
np.fmax(dc_mu_desfuzzy["mu_mc"], dc_mu_desfuzzy["mu_nc"]))
centroid = fuzz.defuzz(dc_param_range["doc"], aggregated, 'centroid')
if k == 0:
name = "nc"
else:
name = "sc"
dic_defuzzy_centroids.update({"{}_centroid".format(name): centroid})
return dic_defuzzy_centroids
[docs]def correct_degree_of_clogging(dc_defuzzy_centroids, degree_of_clogging):
"""
Function to correct degree of clogging from the interval [centroid_of_no_clogging, centroid_of_strong_clogging]
to [0, 1]
Args:
degree_of_clogging (float): original degree of clogging
dc_defuzzy_centroids (dict): two float values that represent the centroids of sc and nc defuzzi-functions
Returns:
degree_of_clogging_corrected (float): degree of clogging in the interval [0, 1]
"""
# define limits of old and new scale
old_scale_low_limit = dc_defuzzy_centroids["nc_centroid"]
old_scale_high_limit = dc_defuzzy_centroids["sc_centroid"]
# transform de scale linearly to [0,1] scale and compute corrected degree of clogging
degree_of_clogging_corrected = (degree_of_clogging - old_scale_low_limit) \
/ (old_scale_high_limit - old_scale_low_limit)
return degree_of_clogging_corrected
[docs]def add_columns(df_samples):
"""
Function to add columns of csv output
Args:
df_samples (Dataframe): dataframe with the parameters of the samples
Returns:
df_samples (Dataframe): same input Dataframe but with new columns
"""
columns = ["dc_c", "dc", # degree of clogging corrected and initial
"mu_nc", "mu_mc", "mu_sc", # membership of defuzzified functions
"mu_fsf_low", "mu_fsf_high", # membership of fuzzy functions
"mu_kf_low", "mu_kf_high",
"mu_n_low", "mu_n_high",
"mu_idoc_low", "mu_idoc_high",
"mu_ratio_low", "mu_ratio_high"
]
df_samples[columns] = np.nan
return df_samples
[docs]def add_results(df, step, degree_of_clogging_corrected, degree_of_clogging, dc_mu_desfuzzy_values, dc_af):
"""
Function to add computed result to output-Dataframe
Args:
df (Dataframe): input Dataframe
step (int): nth sample
degree_of_clogging_corrected (float): dregree of clogging corrected to interval [0, 1]
degree_of_clogging (float): degree of clogging in the
interval [centroid_of_no_clogging, centroid_of_strong_clogging]
dc_mu_desfuzzy_values (dict): three float values of the sample-activated defuzzification functions
dc_af (dict): membership float values of the activated fuzzy functions
step (int): nth sample
Returns:
df (Dataframe): output Dataframe
"""
# add degree of clogging
df.loc[step, ["dc_c", "dc"]] = [degree_of_clogging_corrected, degree_of_clogging]
# add membership functions of defuzzification functions
df.loc[step, ["mu_nc", "mu_mc", "mu_sc"]] = [dc_mu_desfuzzy_values["mu_nc"],
dc_mu_desfuzzy_values["mu_mc"],
dc_mu_desfuzzy_values["mu_sc"]
]
for i, mu in enumerate(dc_af.values()):
df.iloc[step, (i + 12)] = mu
return df