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_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 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
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