def make_prlc_rand(): md_RLC_rand = ( gr.Model("RLC with component tolerances") >> gr.cp_vec_function( fun=lambda df: gr.df_make( Rr=df.R * (1 + df.dR), Lr=df.L * (1 + df.dL), Cr=df.C * (1 + df.dC), ), var=["R", "dR", "L", "dL", "C", "dC"], out=["Rr", "Lr", "Cr"], ) >> gr.cp_vec_function( fun=lambda df: gr.df_make(omega0=np.sqrt(1 / df.Lr / df.Cr)), var=["Lr", "Cr"], out=["omega0"], ) >> gr.cp_vec_function( fun=lambda df: gr.df_make(Q=df.omega0 * df.Rr * df.Cr), name="parallel RLC", var=["omega0", "Rr", "Cr"], out=["Q"]) >> gr.cp_bounds( R=(1e-3, 1e0), L=(1e-9, 1e-3), C=(1e-3, 100), ) >> gr.cp_marginals( dR=dict(dist="uniform", loc=R_percent_lo, scale=R_percent_up - R_percent_lo), dL=dict(dist="uniform", loc=L_percent_lo, scale=L_percent_up - L_percent_lo), dC=dict(dist="uniform", loc=C_percent_lo, scale=C_percent_up - C_percent_lo), ) >> gr.cp_copula_independence()) return md_RLC_rand
def make_tlmc_model_2f1m(): import numpy as np import grama as gr def fun_lev0(x): # evaluate level 0 function at x, record cost P = x cost = 1 return P, cost def fun_lev1(x): # evaluate level 1 function at x, record cost P = np.sin(x) cost = 2 return P, cost md = gr.Model(name = "tlmc_model") >> \ gr.cp_function( fun = fun_lev0, var = ["x"], out = ["P0" , "cost0"], name = ["level 0 function"] ) >> \ gr.cp_function( fun = fun_lev1, var = ["x"], out = ["P1" , "cost1"], name = ["level 1 function"] ) >> \ gr.cp_marginals( x = {"dist": "norm", "loc": 0, "scale": 1, "sign": +1}) >> \ gr.cp_copula_independence return md
def make_test(): md = Model() >> \ cp_function(fun=fun, var=3, out=1) >> \ cp_bounds(x0=(-1,+1), x1=(-1,+1), x2=(-1,+1)) >> \ cp_marginals( x0={"dist": "uniform", "loc": -1, "scale": 2}, x1={"dist": "uniform", "loc": -1, "scale": 2} ) >> \ cp_copula_independence() return md
def make_plate_buckle(): r"""Initialize a buckling plate model Variables (deterministic): w (in): Plate width h (in): Plate height t (in): Plate thickness m (-): Wavenumber L (kips): Applied (compressive) load; uniformly applied along top and bottom edges Variables (random): E (kips/in^2): Elasticity mu (-): Poisson's ratio Outputs: k_cr (-): Prefactor for buckling stress g_buckle (kips/in^2): Buckling limit state: critical stress - applied stress """ md = ( Model("Plate Buckling") >> cp_vec_function( fun=lambda df: df_make( k_cr=(df.m*df.h/df.w + df.w/df.m/df.h)**2 ), var=["w", "h", "m"], out=["k_cr"], ) >> cp_vec_function( fun=lambda df: df_make( g_buckle=df.k_cr * pi**2/12 * df.E / (1 - df.mu**2) * (df.t/df.h)**2 - df.L / df.t / df.w ), var=["k_cr", "t", "h", "w", "E", "mu", "L"], out=["g_buckle"], name="limit state", ) >> cp_bounds( t=(0.5 * THICKNESS, 2 * THICKNESS), h=(6, 18), w=(6, 18), m=(1, 5), L=(LOAD / 2, LOAD * 2), ) >> cp_marginals( E=marg_fit("norm", df_stang.E), mu=marg_fit("beta", df_stang.mu), ) >> cp_copula_gaussian(df_data=df_stang) ) return md
def make_poly(): md = gr.Model("Polynomials") >> \ gr.cp_function(fun=lambda x: x, var=1, out=1, name="linear") >> \ gr.cp_function(fun=lambda x: x**2, var=1, out=1, name="quadratic") >> \ gr.cp_function(fun=lambda x: x**3, var=1, out=1, name="cubic") >> \ gr.cp_marginals( x0={"dist": "uniform", "loc": -1, "scale": 2}, x1={"dist": "uniform", "loc": -1, "scale": 2}, x2={"dist": "uniform", "loc": -1, "scale": 2} ) >> \ gr.cp_copula_independence() return md
def make_ishigami(): """Ishigami function The Ishigami function is commonly used as a test case for estimating Sobol' indices. Model definition: y0 = sin(x1) + a sin(x2)^2 + b x3^4 sin(x1) x1 ~ U[-pi, +pi] x2 ~ U[-pi, +pi] x3 ~ U[-pi, +pi] Sobol' index data: V[y0] = a^2/8 + b pi^4/5 + b^2 pi^8/18 + 0.5 T1 = 0.5(1 + b pi^4/5)^2 T2 = a^2/8 T3 = 0 Tt1 = 0.5(1 + b pi^4/5)^2 + 8 b^2 pi^8/225 Tt2 = a^2/8 Tt3 = 8 b^2 pi^8/225 References: T. Ishigami and T. Homma, βAn importance quantification technique in uncertainty analysis for computer models,β In the First International Symposium on Uncertainty Modeling and Analysis, Maryland, USA, Dec. 3β5, 1990. DOI:10.1109/SUMA.1990.151285 """ md = gr.Model(name = "Ishigami Function") >> \ gr.cp_function( fun=fun, var=["a", "b", "x1", "x2", "x3"], out=1 ) >> \ gr.cp_bounds(a=(6.0, 8.0), b=(0, 0.2)) >> \ gr.cp_marginals( x1={"dist": "uniform", "loc": -np.pi, "scale": 2 * np.pi}, x2={"dist": "uniform", "loc": -np.pi, "scale": 2 * np.pi}, x3={"dist": "uniform", "loc": -np.pi, "scale": 2 * np.pi} ) >> \ gr.cp_copula_independence() return md
def make_channel_nondim(): r"""Make 1d channel model; dimensionless form Instantiates a model for particle and fluid temperature rise; particles are suspended in a fluid with bulk velocity along a square cross-section channel. The walls of said channel are transparent, and radiation heats the particles as they travel down the channel. References: Banko, A.J. "RADIATION ABSORPTION BY INERTIAL PARTICLES IN A TURBULENT SQUARE DUCT FLOW" (2018) PhD Thesis, Stanford University, Chapter 2 """ md = ( Model("1d Particle-laden Channel with Radiation; Dimensionless Form") >> cp_vec_function( fun=lambda df: df_make(beta=120 * (1 + df.Phi_M * df.chi)), var=["Phi_M", "chi"], out=["beta"], ) >> cp_vec_function( fun=lambda df: df_make( T_f=(df.Phi_M * df.chi) / (1 + df.Phi_M * df.chi) * (df.I * df.xst - df.beta**(-1) * df.I * (1 - exp(-df.beta * df.xst))), T_p=1 / (1 + df.Phi_M * df.chi) * (df.Phi_M * df.chi * df.I * df.xst + df.beta**(-1) * df.I * (1 - exp(-df.beta * df.xst))), ), var=["xst", "Phi_M", "chi", "I", "beta"], out=["T_f", "T_p"], ) >> cp_bounds( ## Dimensionless axial location (-) xst=(0, 5), ) >> cp_marginals( ## Mass loading ratio (-) Phi_M={ "dist": "uniform", "loc": 0, "scale": 1 }, ## Particle-fluid heat capacity ratio (-) chi={ "dist": "uniform", "loc": 0.1, "scale": 0.9 }, ## Normalized radiative intensity (-) I={ "dist": "uniform", "loc": 0.1, "scale": 0.9 }, ) >> cp_copula_independence()) return md
def make_linear_normal(): md = Model("Linear-Normal Reliability Problem") >> \ cp_function( fun=limit_state, var=2, out=["g_linear"], name="limit state" ) >> \ cp_marginals( x0={"dist": "norm", "loc": 0, "scale": 1, "sign":+1}, x1={"dist": "norm", "loc": 0, "scale": 1, "sign":+1} ) >> \ cp_copula_independence() return md
def make_pareto_random(twoDim=True): """ Create a model of random points for a pareto frontier evaluation Args: twoDim (bool): determines whether to create a 2D or 3D model """ if twoDim == True: # Model to make dataset md_true = (Model() >> cp_vec_function( fun=lambda df: df_make( y1=df.x1 * cos(df.x2), y2=df.x1 * sin(df.x2), ), var=["x1", "x2"], out=["y1", "y2"], ) >> cp_marginals( x1=dict(dist="uniform", loc=0, scale=1), x2=dict(dist="uniform", loc=0, scale=pi / 2), ) >> cp_copula_independence()) return md_true else: # Model to make dataset md_true = (Model() >> cp_vec_function( fun=lambda df: df_make( y1=df.x1 * cos(df.x2), y2=df.x1 * sin(df.x2), y3=df.x1 * tan(df.x2), ), var=["x1", "x2", "x3"], out=["y1", "y2", "y3"], ) >> cp_marginals(x1=dict(dist="uniform", loc=0, scale=1), x2=dict(dist="uniform", loc=0, scale=pi / 2), x3=dict(dist="uniform", loc=0, scale=pi / 4)) >> cp_copula_independence()) return md_true
def make_plate_buckle(): md = (gr.Model("Plate Buckling") >> gr.cp_function( fun=function_buckle_state, var=["t", "h", "w", "E", "mu", "L"], out=["g_buckle"], name="limit state", ) >> gr.cp_bounds( t=(0.5 * THICKNESS, 2 * THICKNESS), h=(6, 18), w=(6, 18), L=(LOAD / 2, LOAD * 2), ) >> gr.cp_marginals(E=gr.marg_named(df_stang.E, "norm"), mu=gr.marg_named(df_stang.mu, "beta")) >> gr.cp_copula_gaussian(df_data=df_stang)) return md
def md_gen(fun_gen, num_levs): import grama as gr models = list() costs = list() for i in range(num_levs): md = gr.Model(name = ("md{}".format(i))) >> \ gr.cp_function( fun = fun_gen(10**(i+1)), var = ["x"], out = ["P"], name = ["level 0 function"] ) >> \ gr.cp_marginals( x = {"dist": "norm", "loc": 0.5, "scale": 0.2, "sign": +1}) >> \ gr.cp_copula_independence models.append(md) md_cost = i + 1 costs.append(md_cost) return models, costs
def make_tlmc_model_1f1m(): import numpy as np import grama as gr def fun_lev(args): # evaluate level "lev" function at x, record cost level, x = args def fun_lev0(x): # evaluate level 0 function at x, record cost P = x cost = 1 return P, cost def fun_lev1(x): # evaluate level 1 function at x, record cost P = np.sin(x) cost = 2 return P, cost if level == 0: fun = fun_lev0 elif level == 1: fun = fun_lev1 else: raise ValueError('Input level too high') P, cost = fun(x) return P, cost md = gr.Model(name = "tlmc_model_1f1m") >> \ gr.cp_function( fun = fun_lev, var = ["level", "x"], out = ["P" , "cost"], name = ["level function"] ) >> \ gr.cp_marginals( x = {"dist": "norm", "loc": 0, "scale": 1, "sign": +1}) >> \ gr.cp_copula_independence return md
def fit_nls( df_data, md=None, out=None, var_fix=None, df_init=None, verbose=True, uq_method=None, **kwargs, ): r"""Fit a model with Nonlinear Least Squares (NLS) Estimate best-fit variable levels with nonlinear least squares (NLS), and return an executable model with those frozen best-fit levels. Optionally, fit a distribution on the parameters to quantify parametric uncertainty. Note: This is a *synonym* for eval_nls(); see the documentation for eval_nls() for keyword argument options available beyond those listed here. Args: df_data (DataFrame): Data for estimating best-fit variable levels. Variables not found in df_data optimized for fitting. md (gr.Model): Model to analyze. All model variables selected for fitting must be bounded or random. Deterministic variables may have semi-infinite bounds. var_fix (list or None): Variables to fix to nominal levels. Note that variables with domain width zero will automatically be fixed. df_init (DataFrame): Initial guesses for parameters; overrides n_restart n_restart (int): Number of restarts to try; the first try is at the nominal conditions of the model. Returned model will use the least-error parameter set among restarts tested. n_maxiter (int): Optimizer maximum iterations verbose (bool): Print best-fit parameters to console? uq_method (str OR None): If string, select method to quantify parameter uncertainties. If None, provide best-fit values only. Methods: uq_method = "linpool": assume normal errors; linearly approximate parameter effects; equally pool variance matrices for each output Returns: gr.Model: Model for evaluation with best-fit variables frozen to optimized levels. Examples: >>> import grama as gr >>> from grama.data import df_trajectory_windowed >>> from grama.models import make_trajectory_linear >>> X = gr.Intention() >>> >>> md_trajectory = make_trajectory_linear() >>> md_fitted = ( >>> df_trajectory_windowed >>> >> gr.ft_nls( >>> md=md_trajectory, >>> uq_method="linpool", >>> ) >>> ) """ ## Check `out` invariants if out is None: out = md.out print("... fit_nls setting out = {}".format(out)) ## Check invariants if md is None: raise ValueError("Must provide model md") ## Determine variables to be fixed if var_fix is None: var_fix = set() else: var_fix = set(var_fix) for var in md.var_det: wid = md.domain.get_width(var) if wid == 0: var_fix.add(var) ## Run eval_nls to fit model parameter values df_fit = eval_nls( md, df_data=df_data, var_fix=var_fix, df_init=df_init, append=True, verbose=verbose, **kwargs, ) ## Select best-fit values df_best = df_fit.sort_values(by="mse", axis=0).iloc[[0]].reset_index(drop=True) if verbose: print(df_fit.sort_values(by="mse", axis=0)) ## Determine variables that were fitted var_fitted = list(set(md.var).intersection(set(df_best.columns))) var_remain = list(set(md.var).difference(set(var_fitted))) if len(var_remain) == 0: raise ValueError("Resulting model is constant!") ## Assemble and return fitted model if md.name is None: name = "(Fitted Model)" else: name = md.name + " (Fitted)" ## Calibrate parametric uncertainty, if requested if uq_method == "linpool": ## Precompute data df_nom = eval_nominal(md, df_det="nom") df_base = tran_outer( df_data, concat((df_best[var_fitted], df_nom[var_fix]), axis=1)) df_pred = eval_df(md, df=df_base) df_grad = eval_grad_fd(md, df_base=df_base, var=var_fitted) ## Pool variance matrices n_obs = df_data.shape[0] n_fitted = len(var_fitted) Sigma_pooled = zeros((n_fitted, n_fitted)) for output in out: ## Approximate sigma_sq sigma_sq = npsum( nppow(df_data[output].values - df_pred[output].values, 2)) / (n_obs - n_fitted) ## Approximate (pseudo)-inverse hessian var_grad = list(map(lambda v: "D" + output + "_D" + v, var_fitted)) Z = df_grad[var_grad].values Hinv = pinv(Z.T.dot(Z), hermitian=True) ## Add variance matrix to pooled Sigma Sigma_pooled = Sigma_pooled + sigma_sq * Hinv / n_fitted ## Check model for identifiability kappa_out = cond(Sigma_pooled) if kappa_out > 1e10: warn( "Model is locally unidentifiable as measured by the " + "condition number of the pooled covariance matrix; " + "kappa = {}".format(kappa_out), RuntimeWarning, ) ## Convert to std deviations and correlation sigma_comp = npsqrt(diag(Sigma_pooled)) corr_mat = Sigma_pooled / (atleast_2d(sigma_comp).T.dot( atleast_2d(sigma_comp))) corr_data = [] I, J = triu_indices(n_fitted, k=1) for ind in range(len(I)): i = I[ind] j = J[ind] corr_data.append([var_fitted[i], var_fitted[j], corr_mat[i, j]]) df_corr = DataFrame(data=corr_data, columns=["var1", "var2", "corr"]) ## Assemble marginals marginals = {} for ind, var_ in enumerate(var_fitted): marginals[var_] = { "dist": "norm", "loc": df_best[var_].values[0], "scale": sigma_comp[ind], } ## Construct model with Gaussian copula if len(var_fix) > 0: md_res = (Model(name) >> cp_function( lambda x: df_nom[var_fix].values, var=set(var_remain).difference(var_fix), out=var_fix, name="Fix variable levels", ) >> cp_md_det(md=md) >> cp_marginals(**marginals) >> cp_copula_gaussian(df_corr=df_corr)) else: md_res = (Model(name) >> cp_md_det(md=md) >> cp_marginals( **marginals) >> cp_copula_gaussian(df_corr=df_corr)) ## Return deterministic model elif uq_method is None: md_res = (Model(name) >> cp_function( lambda x: df_best[var_fitted].values, var=var_remain, out=var_fitted, name="Fix variable levels", ) >> cp_md_det(md=md)) else: raise ValueError( "uq_method option {} not recognized".format(uq_method)) return md_res
def make_cantilever_beam(): """Cantilever beam A standard reliability test-case, often used for benchmarking reliability analysis and design algorithms. Generally used in the following optimization problem: min_{w,t} c_area s.t. P[g_stress <= 0] <= 1.35e-3 P[g_disp <= 0] <= 1.35e-3 1 <= w, t <= 4 Deterministic Variables: w: Beam width t: Beam thickness Random Variables: H: Horizontal applied force V: Vertical applied force E: Elastic modulus Y: Yield stress Outputs: c_area: Cost; beam cross-sectional area g_stress: Limit state; stress g_disp: Limit state; tip displacement References: Wu, Y.-T., Shin, Y., Sues, R., and Cesare, M., "Safety-factor based approach for probability-based design optimization," American Institute of Aeronautics and Astronautics, Seattle, Washington, April 2001. Sues, R., Aminpour, M., and Shin, Y., "Reliability-based Multi-Disciplinary Optimiation for Aerospace Systems," American Institute of Aeronautics and Astronautics, Seattle, Washington, April 2001. """ md = Model(name = "Cantilever Beam") >> \ cp_vec_function( fun=function_area, var=["w", "t"], out=["c_area"], name="cross-sectional area", runtime=1.717e-7 ) >> \ cp_vec_function( fun=function_stress, var=["w", "t", "H", "V", "E", "Y"], out=["g_stress"], name="limit state: stress", runtime=8.88e-7 ) >> \ cp_vec_function( fun=function_displacement, var=["w", "t", "H", "V", "E", "Y"], out=["g_disp"], name="limit state: displacement", runtime=3.97e-6 ) >> \ cp_bounds( w=(2, 4), t=(2, 4) ) >> \ cp_marginals( H={"dist": "norm", "loc": MU_H, "scale": TAU_H, "sign": +1}, V={"dist": "norm", "loc": MU_V, "scale": TAU_V, "sign": +1}, E={"dist": "norm", "loc": MU_E, "scale": TAU_E, "sign": 0}, Y={"dist": "norm", "loc": MU_Y, "scale": TAU_Y, "sign": -1} ) >> \ cp_copula_independence() return md
def make_channel(): r"""Make 1d channel model; dimensional form Instantiates a model for particle and fluid temperature rise; particles are suspended in a fluid with bulk velocity along a square cross-section channel. The walls of said channel are transparent, and radiation heats the particles as they travel down the channel. Note that this takes the same inputs as the builtin dataset `df_channel`. References: Banko, A.J. "RADIATION ABSORPTION BY INERTIAL PARTICLES IN A TURBULENT SQUARE DUCT FLOW" (2018) PhD Thesis, Stanford University, Chapter 2 Examples: >>> import grama as gr >>> from grama.data import df_channel >>> from grama.models import make_channel >>> md_channel = make_channel() >>> ( >>> df_channel >>> >> gr.tf_md(md_channel) >>> >> gr.ggplot(gr.aes("T_f", "T_norm")) >>> + gr.geom_abline(slope=1, intercept=0, linetype="dashed") >>> + gr.geom_point() >>> + gr.labs(x="1D Model", y="3D DNS") >>> ) """ md = ( Model("1d Particle-laden Channel with Radiation; Dimensional Form") >> cp_vec_function( fun=lambda df: df_make( Re=df.U * df.H / df.nu_f, chi=df.cp_p / df.cp_f, Pr=df.nu_f / df.alpha_f, Phi_M=df.rho_p * 0.524 * df.d_p**3 * df.n / df.rho_f, tau_flow=df.L / df.U, tau_pt=(df.rho_p * df.cp_p * 0.318 * df.d_p) / df.h_p, tau_rad=(df.rho_p * df.cp_p * 0.667 * df.d_p * df.T_0) / (df.Q_abs * 0.78 * df.I_0), ), var=[ "U", # Fluid bulk velocity "H", # Channel width "nu_f", # Fluid kinematic viscosity "cp_p", # Particle isobaric heat capacity "cp_f", # Fluid isobaric heat capacity "alpha_f", # Fluid thermal diffusivity "rho_p", # Particle density "rho_f", # Fluid density "d_p", # Particle diameter "n", # Particle number density "h_p", # Particle-to-gas convection coefficient "T_0", # Initial temperature "Q_abs", # Particle radiation absorption coefficient "I_0", # Incident radiation ], out=[ "Re", # Reynolds number "Pr", # Prandtl number "chi", # Particle-fluid heat capacity ratio "Phi_M", # Mass Loading Ratio "tau_flow", # Fluid residence time "tau_pt", # Particle thermal time constant "tau_rad", # Particle temperature doubling time (approximate) ], name="Dimensionless Numbers", ) >> cp_vec_function( fun=lambda df: df_make( ## Let xi = x / L xst=(df.xi * df.L) / df.H / df.Re / df.Pr, ## Assume an optically-thin scenario; I/I_0 = 1 Is=df.Re * df.Pr * (df.H / df.L) * (df.tau_flow / df.tau_rad) * 1, beta=df.Re * df.Pr * (df.H / df.L) * (df.tau_flow / df.tau_pt) * (1 + df.Phi_M * df.chi), ), var=[ "xi", "chi", "H", "L", "Phi_M", "tau_flow", "tau_rad", "tau_pt" ], out=[ "xst", # Flow-normalized channel axial location "Is", # Normalized heat flux "beta", # Spatial development coefficient ], name="Intermediate Dimensionless Numbers", ) >> cp_vec_function( fun=lambda df: df_make( T_f=(df.Phi_M * df.chi) / (1 + df.Phi_M * df.chi) * (df.Is * df.xst - df.Is / df.beta * (1 - exp(-df.beta * df.xst))), T_p=1 / (1 + df.Phi_M * df.chi) * (df.Phi_M * df.chi * df.Is * df.xst + df.Is / df.beta * (1 - exp(-df.beta * df.xst))), ), var=["xst", "Phi_M", "chi", "Is", "beta"], out=["T_f", "T_p"], ) >> cp_bounds( ## Normalized axial location; xi = x/L (-) xi=(0, 1), ) >> cp_marginals( ## Channel width (m) H={ "dist": "uniform", "loc": 0.038, "scale": 0.004 }, ## Channel length (m) L={ "dist": "uniform", "loc": 0.152, "scale": 0.016 }, ## Fluid bulk velocity (m/s) U={ "dist": "uniform", "loc": 1, "scale": 2.5 }, ## Fluid kinematic viscosity (m^2/s) nu_f={ "dist": "uniform", "loc": 1.4e-5, "scale": 0.1e-5 }, ## Particle isobaric heat capacity (J/(kg K)) cp_p={ "dist": "uniform", "loc": 100, "scale": 900 }, ## Fluid isobaric heat capacity (J/(kg K)) cp_f={ "dist": "uniform", "loc": 1000, "scale": 1000 }, ## Fluid thermal diffusivity (m^2/s) alpha_f={ "dist": "uniform", "loc": 50e-6, "scale": 50e-6 }, ## Particle density (kg / m^3) rho_p={ "dist": "uniform", "loc": 1e3, "scale": 9e3 }, ## Fluid density (kg / m^3) rho_f={ "dist": "uniform", "loc": 0.5, "scale": 1.0 }, ## Particle diameter (m) d_p={ "dist": "uniform", "loc": 1e-6, "scale": 9e-6 }, ## Particle number density (1 / m^3) n={ "dist": "uniform", "loc": 9.5e9, "scale": 1.0e9 }, ## Particle-to-gas convection coefficient (W / (m^2 K)) h_p={ "dist": "uniform", "loc": 1e3, "scale": 9e3 }, ## Initial temperature (K) T_0={ "dist": "uniform", "loc": 285, "scale": 30 }, ## Particle radiation absorption coefficient (-) Q_abs={ "dist": "uniform", "loc": 0.25, "scale": 0.50 }, ## Incident radiation (W/m^2) I_0={ "dist": "uniform", "loc": 9.5e6, "scale": 1.0e6 }, ) >> cp_copula_independence()) return md
var_applied = ["L", "w", "t"] out_applied = ["sig_app"] def fun_limit(x): sig_cr, sig_app = x return sig_cr - sig_app var_limit = ["sig_cr", "sig_app"] out_limit = ["safety"] ## Build model md_plate = ( gr.Model("Plate under buckling load") >> gr.cp_function( fun=fun_critical, var=var_critical, out=out_critical, name="Critical") >> gr.cp_function( fun=fun_applied, var=var_applied, out=out_applied, name="Applied") >> gr.cp_function(fun=fun_limit, var=var_limit, out=out_limit, name="Safety") >> gr.cp_bounds( # Deterministic variables t=(0.03, 0.12), # Thickness w=(6, 18), # Width h=(6, 18), # Height L=(2.5e-1, 4.0e-1), # Load ) >> gr.cp_marginals( # Random variables E=gr.marg_gkde(df_stang.E), mu=gr.marg_gkde(df_stang.mu)) >> gr.cp_copula_gaussian(df_data=df_stang)) # Dependence