Spaces:
Sleeping
Sleeping
Download main.py from osel-dbcms/Justify: direct link, hf CLI and curl.
- Browser
- Download file 13.7 kB
-
https://huggingface.co/spaces/osel-dbcms/Justify/resolve/main/main.py
- Command line
-
hf download hf://spaces/osel-dbcms/Justify/main.py
-
curl -L -o main.py https://huggingface.co/spaces/osel-dbcms/Justify/resolve/main/main.py
13.7 kB
| from dash import Dash, Input, Output, State, no_update | |
| from data.functions import * | |
| from transportEqs import * | |
| from Kps_function.read_Kps_model import * | |
| import os | |
| from figure import build_figure | |
| from main_layout import build_main_layout | |
| from instructions import build_instructions_layout | |
| from rst_info import build_rst_layout | |
| from dash import html, dcc | |
| import base64 | |
| import io | |
| app = Dash( | |
| __name__, | |
| assets_folder=os.path.join(os.path.dirname(__file__), "assets"), | |
| suppress_callback_exceptions=True, | |
| #external_stylesheets=[dbc.themes.BOOTSTRAP], | |
| ) | |
| # -------------------------------------------------------------------- | |
| # Layout | |
| # -------------------------------------------------------------------- | |
| app.layout = html.Div([ | |
| dcc.Location(id="url", refresh=False), | |
| html.Header( | |
| html.Div([ | |
| html.A( | |
| html.Img( | |
| src="/assets/gov-fda-new-white.svg", | |
| alt="U.S. Food and Drug Administration", | |
| className="fda-logo", | |
| ), | |
| href="https://www.fda.gov", | |
| target="_blank", | |
| className="site-brand", | |
| ), | |
| html.Span( | |
| "Extraction condition justification tool", | |
| className="site-tool-title", | |
| ), | |
| html.Nav([ | |
| dcc.Link("Model", href="/"), | |
| dcc.Link("Quick start", href="/instructions"), | |
| dcc.Link("About this tool", href="/rst"), | |
| ], className="site-nav", **{"aria-label": "Main navigation"}), | |
| ], className="site-container site-header-inner"), | |
| className="site-header", | |
| ), | |
| html.Main( | |
| html.Div(id="page-content"), | |
| id="main-content", | |
| className="site-container site-main", | |
| ), | |
| html.Footer( | |
| html.Div("Office of Science and Engineering Laboratories · Contact", className="site-container"), | |
| className="site-footer", | |
| ), | |
| ]) | |
| app.validation_layout = html.Div([ | |
| app.layout, | |
| build_main_layout(), | |
| build_instructions_layout(), | |
| build_rst_layout(), | |
| ]) | |
| def route(pathname): | |
| if pathname == "/instructions": | |
| return build_instructions_layout() | |
| elif pathname == "/rst": | |
| return build_rst_layout() | |
| else: | |
| return build_main_layout() | |
| # -------------------------------------------------------------------- | |
| # Callbacks | |
| # -------------------------------------------------------------------- | |
| def show_solute_upload(solute_source): | |
| if solute_source == "upload": | |
| return {"display": "block"} | |
| return {"display": "none"} | |
| def load_solute_file(contents, filename): | |
| if contents is None: | |
| return None, "" | |
| try: | |
| content_type, content_string = contents.split(",") | |
| decoded = base64.b64decode(content_string) | |
| uploaded_df = pd.read_excel( | |
| io.BytesIO(decoded) | |
| ) | |
| required_columns = [ | |
| "CASRN", | |
| "MW", | |
| "LogP", | |
| #"Vabc", | |
| ] | |
| missing = [ | |
| col for col in required_columns | |
| if col not in uploaded_df.columns | |
| ] | |
| if missing: | |
| return ( | |
| None, | |
| f"Missing required columns: {', '.join(missing)}" | |
| ) | |
| numeric_columns = [ | |
| "MW", | |
| "LogP", | |
| #"Vabc", | |
| ] | |
| for col in numeric_columns: | |
| uploaded_df[col] = pd.to_numeric( | |
| uploaded_df[col], | |
| errors="coerce" | |
| ) | |
| if uploaded_df[numeric_columns].isna().any().any(): | |
| return ( | |
| None, | |
| "One or more required numeric values are missing or invalid." | |
| ) | |
| return ( | |
| uploaded_df.to_dict("records"), | |
| f"Loaded {len(uploaded_df)} solutes from {filename}" | |
| ) | |
| except Exception as e: | |
| return None, f"Could not read file: {e}" | |
| def toggle_condition1_inputs(mode, current_value): | |
| disable = (mode != "in_vitro") | |
| return disable, disable, disable, disable, disable | |
| def toggle_condition2_inputs(mode, current_value): | |
| disable = (mode != "in_vitro") | |
| return disable, disable, disable, disable, disable | |
| def update_chart(n_clicks, | |
| matrix, tg, crystal, density, polymer_volume, surface_area, | |
| c1_mode, c1_solvent, c1_volume, c1_swelling, | |
| c1_temp, c1_time, c1_iter, | |
| c2_mode, c2_solvent, c2_volume, | |
| c2_swelling, c2_temp, c2_time, c2_iter,samples,mc_option,solute_source,uploaded_solute_data): | |
| # --------------------------------------------------------- | |
| # Validate solute source | |
| # --------------------------------------------------------- | |
| if solute_source == "default": | |
| current_soluteData = soluteData.copy() | |
| elif solute_source == "upload": | |
| if not uploaded_solute_data: | |
| return ( | |
| no_update, | |
| "Please upload a valid Excel file before calculating." | |
| ) | |
| current_soluteData = pd.DataFrame.from_records( | |
| uploaded_solute_data | |
| ) | |
| else: | |
| return ( | |
| no_update, | |
| "Please select either the default or user-defined chemical set." | |
| ) | |
| df = pd.DataFrame() | |
| df['CASRN'] = current_soluteData['CASRN'].to_numpy() | |
| current_soluteData["LogP"] = current_soluteData["LogP"].clip(upper=10) | |
| current_soluteData["Vabc"] = current_soluteData["MW"] | |
| N = int(samples) | |
| pindex = np.where(polymers == matrix)[0][0] | |
| CHRIS_category = categories[pindex] | |
| Polymer_Density = float(density) | |
| Polymer_Tg = float(tg) + 273.15 | |
| Polymer_X = float(crystal)/100. | |
| L = float(polymer_volume)/float(surface_area) | |
| # Condition 1 | |
| ExtractionTime = float(c1_time) * 3600. | |
| if c1_mode == 'in_vivo_conservative': | |
| c1_dist = ConservativeMonteCarlo(current_soluteData, CHRIS_category, L, ExtractionTime, N) | |
| elif c1_mode == 'in_vivo_tissue': | |
| c1_dist = TissueMonteCarlo(current_soluteData, CHRIS_category, L, ExtractionTime, N) | |
| else: | |
| Solvent_Name = c1_solvent | |
| Solvent_MW = Solvent_MWs[Solvent_Name] | |
| Solvent_Density = Solvent_Densities[Solvent_Name] | |
| Solvent_PI = Solvent_PIs[Solvent_Name] | |
| ExtractionT = float(c1_temp) + 273.15 | |
| Ms_M0 = float(c1_swelling) | |
| Swell = 1.+(Ms_M0-1.)*Polymer_Density/Solvent_Density | |
| w = (Ms_M0 - 1.)/(Ms_M0-Polymer_X) | |
| Iterations = float(c1_iter) | |
| Lbath = float(c1_volume) / float(surface_area) | |
| c1_dist = ExtractMonteCarlo(current_soluteData, Solvent_PI, w, ExtractionT, Polymer_Tg, Solvent_Name, Solvent_MW, | |
| ExtractionTime, Swell, Iterations, CHRIS_category, L, Lbath, N) | |
| # Condition 2 | |
| ExtractionTime = float(c2_time) * 3600. | |
| if c2_mode == 'in_vivo_conservative': | |
| c2_dist = ConservativeMonteCarlo(current_soluteData, CHRIS_category, L, ExtractionTime, N) | |
| elif c2_mode == 'in_vivo_tissue': | |
| c2_dist = TissueMonteCarlo(current_soluteData, CHRIS_category, L, ExtractionTime, N) | |
| else: | |
| Solvent_Name = c2_solvent | |
| Solvent_MW = Solvent_MWs[Solvent_Name] | |
| Solvent_Density = Solvent_Densities[Solvent_Name] | |
| Solvent_PI = Solvent_PIs[Solvent_Name] | |
| ExtractionT = float(c2_temp) + 273.15 | |
| Ms_M0 = float(c2_swelling) | |
| Swell = 1. + (Ms_M0 - 1.) * Polymer_Density / Solvent_Density | |
| w = (Ms_M0 - 1.) / (Ms_M0 - Polymer_X) | |
| Iterations = float(c2_iter) | |
| Lbath = float(c2_volume) / float(surface_area) | |
| c2_dist = ExtractMonteCarlo(current_soluteData, Solvent_PI, w, ExtractionT, Polymer_Tg, Solvent_Name, Solvent_MW, | |
| ExtractionTime, Swell, Iterations, CHRIS_category, L, Lbath, N) | |
| if mc_option == "absolute": | |
| c1_lower, c1_median, c1_upper = np.percentile( | |
| c1_dist, | |
| [25, 50, 75], | |
| axis=1 | |
| ) | |
| c2_lower, c2_median, c2_upper = np.percentile( | |
| c2_dist, | |
| [25, 50, 75], | |
| axis=1 | |
| ) | |
| df['Condition 1'] = c1_median | |
| df['Cond1_err_plus'] = c1_upper - c1_median | |
| df['Cond1_err_minus'] = c1_median - c1_lower | |
| df['Condition 2'] = c2_median | |
| df['Cond2_err_plus'] = c2_upper - c2_median | |
| df['Cond2_err_minus'] = c2_median - c2_lower | |
| elif mc_option == "ratio": | |
| ratio_dist = np.divide( | |
| c1_dist, | |
| c2_dist, | |
| out=np.full_like(c1_dist, np.nan), | |
| where=c2_dist > 0 | |
| ) | |
| ratio_lower, ratio_median, ratio_upper = np.percentile( | |
| ratio_dist, | |
| [25, 50, 75], | |
| axis=1 | |
| ) | |
| df['Ratio'] = ratio_median | |
| df['Ratio_err_plus'] = ratio_upper - ratio_median | |
| df['Ratio_err_minus'] = ratio_median - ratio_lower | |
| fig = build_figure(df, mc_option) | |
| return fig, "" | |
| def ConservativeMonteCarlo(soluteData, CHRIS_category, L, time, N): | |
| nSolutes = len(soluteData) | |
| distributions = zeros((nSolutes, N)) | |
| for iSolute in range(nSolutes): | |
| Solute_MW = soluteData['MW'].iloc[iSolute] | |
| D_CHRIS = get_D_CHRIS( | |
| Solute_MW, | |
| CHRIS_category, | |
| N=N | |
| ) | |
| tau = D_CHRIS * time / L**2 | |
| mass = Conservative(tau) | |
| distributions[iSolute, :] = mass | |
| return distributions | |
| def TissueMonteCarlo(soluteData, CHRIS_category, L, time, N): | |
| nSolutes = len(soluteData) | |
| distributions = zeros((nSolutes, N)) | |
| for iSolute in range(nSolutes): | |
| Solute_MW = soluteData['MW'].iloc[iSolute] | |
| Solute_logP = soluteData['LogP'].iloc[iSolute] | |
| D_CHRIS = get_D_CHRIS( | |
| Solute_MW, | |
| CHRIS_category, | |
| N=N | |
| ) | |
| tau = D_CHRIS * time / L**2 | |
| Dt = get_Dt(N) | |
| Kpt = get_Kpt(Solute_logP, N) | |
| beta = (1. / Kpt) * sqrt(Dt / D_CHRIS) | |
| mass = SolubilityLimited(beta, tau) | |
| distributions[iSolute, :] = mass | |
| return distributions | |
| def ExtractMonteCarlo( | |
| soluteData, Solvent_PI, w, ExtractionT, | |
| Polymer_Tg, Solvent_Name, Solvent_MW, | |
| ExtractionTime, Swell, Iterations, | |
| CHRIS_category, L, Lbath, N): | |
| nSolutes = len(soluteData) | |
| distributions = zeros((nSolutes, N)) | |
| for iSolute in range(nSolutes): | |
| Solute_MW = soluteData['MW'].iloc[iSolute] | |
| Solute_logP = soluteData['LogP'].iloc[iSolute] | |
| Solute_Vabc = soluteData['Vabc'].iloc[iSolute] | |
| if Solvent_Name == 'blood': | |
| Kps = get_Kpb(Solute_logP, N) | |
| else: | |
| ToKPS = array([[Solute_logP, Solvent_PI]]) | |
| model = QuantileGridFromCoeffs( | |
| export_dir='Kps_function/Kps_model' | |
| ) | |
| Kps = 10 ** model.sample( | |
| ToKPS, | |
| n_samples=N | |
| )[0] | |
| D_Extract = get_D_Extract( | |
| w, | |
| ExtractionT, | |
| Polymer_Tg, | |
| Solvent_Name, | |
| Solvent_MW, | |
| Solute_MW, | |
| Solute_Vabc, | |
| CHRIS_category, | |
| N=N | |
| ) | |
| tau = D_Extract * ExtractionTime / L**2 | |
| alpha = Lbath / L / Kps | |
| massExtraction = zeros(N) | |
| for i in range(N): | |
| massExtraction[i] = Extraction( | |
| tau[i], | |
| alpha[i], | |
| Kps[i], | |
| Swell, | |
| Iterations | |
| ) | |
| distributions[iSolute, :] = massExtraction | |
| return distributions | |
| if __name__ == "__main__": | |
| app.run(debug=True) | |