{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "29dae327", "metadata": {}, "outputs": [], "source": [ "import shutil\n", "import os\n", "import platform\n", "from pathlib import Path\n", "from cadet import Cadet\n", "\n", "import os\n", "\n", "from IPython.core.display import display, HTML, clear_output\n", "#display(HTML(\"\"))\n", "\n", "from IPython.display import Image\n", "\n", "# python numeric library\n", "import numpy as np\n", "\n", "# scientific library for python\n", "import scipy\n", "\n", "# addict is a library that makes it easier to create nested dictionaries\n", "from addict import Dict\n", "\n", "# json is a standard text based format and it used in CADETMatch for the configuration file\n", "import json\n", "\n", "# python plotting library\n", "import matplotlib.pyplot as plt\n", "%config InlineBackend.figure_format='svg'\n", "%matplotlib inline\n", "\n", "# jupyter widget support\n", "from ipywidgets import interact, interactive\n", "import ipywidgets as widgets\n", "\n", "# Temporary files for simulation objects\n", "import tempfile\n", "tempfile.tempdir = os.path.join(Path.home())\n", "\n", "import subprocess\n", "import pandas as pd" ] }, { "cell_type": "code", "execution_count": 2, "id": "45e9e8cb", "metadata": {}, "outputs": [], "source": [ "# # Convert lab result to accepted CSV file\n", "# lab_result = pd.read_excel('./u=2.7.xlsx')\n", "# c_ini = 4.762\n", "\n", "# time_min = lab_result['min']\n", "# c = lab_result['c']\n", "\n", "# # Extract targeted time index\n", "# index_list = np.concatenate(([0], np.arange(29, len(time_min)+1, 30)))\n", "\n", "# time_min_select = np.array(time_min[index_list])\n", "# c_select = np.array(c[index_list])\n", "\n", "# # Replace index 0 with 0 ICs\n", "# time_min_select[0] = 0\n", "# c_select[0] = 0\n", "# c_select = c_select.clip(min=0)\n", "# # Convert mins to seconds\n", "# time_sec = time_min_select * 60\n", "\n", "# # denormalize c\n", "# c_sec = c_select*c_ini\n", "\n", "# # Create csv file for Cadet Match\n", "# result_df = pd.DataFrame()\n", "# result_df['Time'] = time_sec\n", "# result_df['c'] = c_sec\n", "\n", "# result_df.to_csv('./u=2.7.csv', index=False, header=False)" ] }, { "cell_type": "code", "execution_count": 3, "id": "8a9feb60", "metadata": {}, "outputs": [], "source": [ "def get_cadet_template(n_units=3, split_components_data=False):\n", " cadet_template = Cadet()\n", " \n", " cadet_template.root.input.model.nunits = n_units\n", " \n", " # Store solution\n", " cadet_template.root.input['return'].split_components_data = split_components_data\n", " cadet_template.root.input['return'].split_ports_data = 0\n", " cadet_template.root.input['return'].unit_000.write_solution_inlet = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_outlet = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_bulk = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_particle = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_solid = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_flux = 1\n", " cadet_template.root.input['return'].unit_000.write_solution_volume = 1\n", " cadet_template.root.input['return'].unit_000.write_coordinates = 1\n", " cadet_template.root.input['return'].unit_000.write_sens_outlet = 1\n", " \n", " for unit in range(n_units):\n", " cadet_template.root.input['return']['unit_{0:03d}'.format(unit)] = cadet_template.root.input['return'].unit_000\n", " \n", " # Tolerances for the time integrator\n", " cadet_template.root.input.solver.time_integrator.abstol = 1e-6\n", " cadet_template.root.input.solver.time_integrator.algtol = 1e-10\n", " cadet_template.root.input.solver.time_integrator.reltol = 1e-6\n", " cadet_template.root.input.solver.time_integrator.init_step_size = 1e-6\n", " cadet_template.root.input.solver.time_integrator.max_steps = 1000000\n", " \n", " # Solver settings\n", " cadet_template.root.input.model.solver.gs_type = 1\n", " cadet_template.root.input.model.solver.max_krylov = 0\n", " cadet_template.root.input.model.solver.max_restarts = 10\n", " cadet_template.root.input.model.solver.schur_safety = 1e-8\n", "\n", " # Run the simulation on single thread\n", " cadet_template.root.input.solver.nthreads = 1\n", " \n", " return cadet_template\n", "\n", "def set_discretization(model, n_bound=None, n_col=20, n_par_types=1):\n", " columns = {'GENERAL_RATE_MODEL', 'LUMPED_RATE_MODEL_WITH_PORES', 'LUMPED_RATE_MODEL_WITHOUT_PORES'}\n", " \n", " \n", " for unit_name, unit in model.root.input.model.items():\n", " if 'unit_' in unit_name and unit.unit_type in columns:\n", " unit.discretization.ncol = n_col\n", " unit.discretization.npar = 5\n", " unit.discretization.npartype = n_par_types\n", " \n", " if n_bound is None:\n", " n_bound = unit.ncomp*[0]\n", " unit.discretization.nbound = n_bound\n", " \n", " unit.discretization.par_disc_type = 'EQUIDISTANT_PAR'\n", " unit.discretization.use_analytic_jacobian = 1\n", " unit.discretization.reconstruction = 'WENO'\n", " unit.discretization.gs_type = 1\n", " unit.discretization.max_krylov = 0\n", " unit.discretization.max_restarts = 10\n", " unit.discretization.schur_safety = 1.0e-8\n", "\n", " unit.discretization.weno.boundary_model = 0\n", " unit.discretization.weno.weno_eps = 1e-10\n", " unit.discretization.weno.weno_order = 3\n", " \n", "def run_simulation(cadet, file_name=None):\n", " if file_name is None:\n", " f = next(tempfile._get_candidate_names())\n", " cadet.filename = os.path.join(tempfile.tempdir, f + '.h5')\n", " else:\n", " cadet.filename = file_name\n", " # save the simulation\n", " cadet.save()\n", "\n", " # run the simulation and load results\n", " data = cadet.run()\n", " cadet.load()\n", " \n", " # Remove files \n", " if file_name is None:\n", " os.remove(os.path.join(tempfile.tempdir, f + '.h5'))\n", "\n", " # Raise error if simulation fails\n", " if data.returncode == 0:\n", " print(\"Simulation completed successfully\")\n", " else:\n", " print(data)\n", " raise Exception(\"Simulation failed\")" ] }, { "cell_type": "code", "execution_count": 4, "id": "68bc856c", "metadata": {}, "outputs": [], "source": [ "def create_langmuir_model(L, u, e, Da, ka, kd, qmax, c0, tmax, col_step, time_step):\n", "\n", " langmuir_model = get_cadet_template(n_units=3)\n", "\n", " # INLET\n", " langmuir_model.root.input.model.unit_000.unit_type = 'INLET'\n", " langmuir_model.root.input.model.unit_000.ncomp = 1\n", " langmuir_model.root.input.model.unit_000.inlet_type = 'PIECEWISE_CUBIC_POLY'\n", "\n", " # Column\n", " langmuir_model.root.input.model.unit_001.unit_type = 'LUMPED_RATE_MODEL_WITHOUT_PORES'\n", " langmuir_model.root.input.model.unit_001.ncomp = 1\n", "\n", " langmuir_model.root.input.model.unit_001.col_length = L\n", " langmuir_model.root.input.model.unit_001.velocity = u / e\n", " langmuir_model.root.input.model.unit_001.total_porosity = e\n", " langmuir_model.root.input.model.unit_001.col_dispersion = Da\n", " \n", " langmuir_model.root.input.model.unit_001.adsorption_model = 'MULTI_COMPONENT_LANGMUIR'\n", "\n", " langmuir_model.root.input.model.unit_001.adsorption.is_kinetic = True\n", " langmuir_model.root.input.model.unit_001.adsorption.mcl_ka = [ka,]\n", " langmuir_model.root.input.model.unit_001.adsorption.mcl_kd = [kd,]\n", " langmuir_model.root.input.model.unit_001.adsorption.mcl_qmax = [qmax,]\n", "\n", " langmuir_model.root.input.model.unit_001.init_c = [0.0,]\n", " langmuir_model.root.input.model.unit_001.init_q = [0.0,]\n", "\n", " ## Outlet\n", " langmuir_model.root.input.model.unit_002.ncomp = 1\n", " langmuir_model.root.input.model.unit_002.unit_type = 'OUTLET'\n", " \n", " set_discretization(langmuir_model, n_bound=[1,], n_col=col_step)\n", "\n", " # Sections and connections\n", " langmuir_model.root.input.solver.sections.nsec = 1\n", " langmuir_model.root.input.solver.sections.section_times = [0.0, tmax]\n", " langmuir_model.root.input.solver.sections.section_continuity = [0,]\n", " \n", " ## Inlet Profile\n", " langmuir_model.root.input.model.unit_000.sec_000.const_coeff = [c0,]\n", " \n", " Q = langmuir_model.root.input.model.unit_001.velocity\n", " \n", " ## Switches\n", " langmuir_model.root.input.model.connections.nswitches = 1\n", " langmuir_model.root.input.model.connections.switch_000.section = 0\n", " langmuir_model.root.input.model.connections.switch_000.connections = [\n", " 0, 1, -1, -1, Q,\n", " 1, 2, -1, -1, Q\n", " ]\n", "\n", " # set the times that the simulator writes out data for\n", " langmuir_model.root.input.solver.user_solution_times = np.linspace(0, tmax, time_step) \n", "\n", " return langmuir_model" ] }, { "cell_type": "code", "execution_count": 5, "id": "5b6c00c9", "metadata": {}, "outputs": [], "source": [ "from addict import Dict\n", "\n", "base_dir = Path('./').absolute()\n", "\n", "match_config = Dict()\n", "match_config.CADETPath = Cadet.cadet_path\n", "match_config.baseDir = base_dir.as_posix()\n", "match_config.resultsDir = 'results'" ] }, { "cell_type": "code", "execution_count": 6, "id": "a2eaaffa", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | 0.0 | \n", "0.0.1 | \n", "
---|---|---|
0 | \n", "6.0 | \n", "0.000000 | \n", "
1 | \n", "12.0 | \n", "0.000000 | \n", "
2 | \n", "18.0 | \n", "0.000000 | \n", "
3 | \n", "24.0 | \n", "0.000000 | \n", "
4 | \n", "30.0 | \n", "0.000000 | \n", "
... | \n", "... | \n", "... | \n", "
1145 | \n", "6876.0 | \n", "4.642390 | \n", "
1146 | \n", "6882.0 | \n", "4.642946 | \n", "
1147 | \n", "6888.0 | \n", "4.643960 | \n", "
1148 | \n", "6894.0 | \n", "4.644739 | \n", "
1149 | \n", "6900.0 | \n", "4.645557 | \n", "
1150 rows × 2 columns
\n", "