{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Four Box Model Use Tutorial\n\n* **ACTM Performer:** JHU-APL;\n* **Author:** Chace Ashcraft (chace.ashcraft@jhuapl.edu)\n\nPyBAMOCS Tutorial\n\nPyBAMOCS uses a simplified box model to simulate the Atlantic meridional overturning circulation (AMOC). The\nimplementation is based on the paper by Gnanadesikan et al.\n(https://journals.ametsoc.org/view/journals/clim/31/22/jcli-d-18-0388.1.xml), which examined the stability of the AMOC.\nThis tutorial assumes that you have downloaded the PyBAMOCs code from the PACMANs repository on GitHub and installed\nPyBAMOCS into your Python environment. Installation instructions for the PyBAMOCS module is provided below. For\nadditional information about installing PyBAMOCS and the PyBAMOCS API, please see the PACMANS repository\n(https://github.com/JHUAPL/PACMANs), and navigate to `box_model/python/`.\n\nThis tutorial is meant to be a tool for getting started using the PyBAMOCS package and the included `box_model`\nfunctionality, and is not meant to be a comprehensive overview of all functions or capabilities of the included code.\nFor a more thorough understanding, please consider viewing the code itself, and the examples in the `scripts` folder.\nThere is also a more extensive tutorial in the form of a Jupyter Notebook in the `notebooks` directory of the PyBAMOCS\nmodule.\n\n# PyBAMOCS Installation\n\nWe recommend installing PyBAMOCS in its own environment using `venv`\n(https://docs.python.org/3/library/venv.html) or `conda`\n(https://conda.io/projects/conda/en/latest/user-guide/install/index.html). Once in your new environment (if desired),\nperform the following steps to install the module.\n\n* Clone the PACMANS repository (https://github.com/JHUAPL/PACMANs)\n    * `git clone https://github.com/JHUAPL/PACMANs.git`\n* Change directories to `box_model/python/`\n    * `cd box_model/python/`\n* Install locally using `pip`\n    * `pip install -e .`\n\nTo execute the snippet:\n\n**Step 1:** Follow the instructions above to install the PyBAMOCS module.\n\n**Step 2:** The snippet itself may be run from the command line as follows:\n\n## % python pybamocs_tutorial.py\n\nWe encourage the interested user to examine the code below to identify the relevant objects and methods required to\nimplement their specific use case.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# .............................................\n# IMPORT STATEMENTS\n# .............................................\n\nimport time\nfrom matplotlib import pyplot as plt\nfrom typing import Union\n\n# Import the `box_model` function and its arguments\nfrom pybamocs.box_model import box_model\nfrom pybamocs.box_model import NORTH_IDX, SOUTH_IDX, LOW_IDX, DEEP_IDX\nfrom pybamocs.box_model_args import (\n    BoxModelBoxDimensions,\n    BoxModelInitConditions,\n    BoxModelTimeStep,\n    BoxModelParameters,\n)\n\n\n# Convenience function\ndef print_box_model_argument_settings(argument: Union[BoxModelBoxDimensions, BoxModelInitConditions,\n                                                      BoxModelTimeStep, BoxModelParameters]) -> None:\n    \"\"\"\n    Print box model settings to console for a given box_model argument.\n    :param argument: One of the box_model argument objects.\n    \"\"\"\n    settings_dict = argument.to_dict()  # Get the settings as a python dictionary\n\n    print(\"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\")\n    # Print each key, value pair in the dictionary\n    for key, value in settings_dict.items():\n        print(f\"{key}={value}\")\n    print(\"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\")\n    print()\n\n\ndef main():\n    print(\"Box model settings are divided into five groups:\")\n    # Each object represents a set of parameters to the model\n    box_model_dimensions = BoxModelBoxDimensions()\n    box_model_initial_conditions = BoxModelInitConditions()\n    box_model_time_settings = BoxModelTimeStep()\n    box_model_parameters = BoxModelParameters()\n\n    # And there is one object for each group as shown above.\n    print(\"------------------------------------------------------------\")\n    print(\"Box Dimensions:\")\n    print_box_model_argument_settings(box_model_dimensions)\n\n    print(\"------------------------------------------------------------\")\n    print(\"Initial Conditions\")\n    print_box_model_argument_settings(box_model_initial_conditions)\n\n    print(\"------------------------------------------------------------\")\n    print(\"Model Time Step Parameters:\")\n    print_box_model_argument_settings(box_model_time_settings)\n\n    print(\"------------------------------------------------------------\")\n    print(\"Model Parameters\")\n    print_box_model_argument_settings(box_model_parameters)\n\n    # To run the box model, simply call the `box_model` function with your argument objects\n    print(\"Running the box model...\")\n    start = time.time()\n    results = box_model(box_model_dimensions,\n                        box_model_initial_conditions,\n                        box_model_parameters,\n                        box_model_time_settings)\n    print(f\"Run complete. Time: {time.time() - start} seconds.\")\n\n    # Note that the results are contained in a BoxModelResult object\n    print(\"Box model output object:\")\n    print(results)\n    print()\n\n    # You can access specific results directly from the object\n    print(\"Result details:\")\n    print(\"------------------------------------------------------\")\n    print(\"Shape of M_n for run:\", results.M_n.shape)\n    print()\n\n    # or you can \"unpack\" them all at once\n    M_n, M_upw, M_eddy, D_low, T, S, sigma0 = results.unpack()\n\n    print(\"------------------------------------------------------\")\n    print(\"First 3 values of each output variable:\")\n    print(\"M_n:\", M_n[:3])\n    print(\"M_upw:\", M_upw[:3])\n    print(\"M_eddy:\", M_eddy[:3])\n    print(\"D_low:\", D_low[:3])\n    print(\"T_north:\", T[NORTH_IDX, :3])\n    print(\"T_south:\", T[SOUTH_IDX, :3])\n    print(\"T_low:\", T[LOW_IDX, :3])\n    print(\"T_deep:\", T[DEEP_IDX, :3])\n    print(\"S_north:\", S[NORTH_IDX, :3])\n    print(\"S_south:\", S[SOUTH_IDX, :3])\n    print(\"S_low:\", S[LOW_IDX, :3])\n    print(\"S_deep:\", S[DEEP_IDX, :3])\n    print(\"sigma0_north:\", sigma0[NORTH_IDX, :3])\n    print(\"sigma0_south:\", sigma0[SOUTH_IDX, :3])\n    print(\"sigma0_low:\", sigma0[LOW_IDX, :3])\n    print(\"sigma0_deep:\", sigma0[DEEP_IDX, :3])\n\n    print(\"Plotting results...\")\n    plt.plot(M_n, label='M_n')\n    plt.plot(M_upw, label='M_upw')\n    plt.plot(M_eddy, label='M_eddy')\n    plt.plot(D_low, label='Dlow')\n    plt.legend()\n    plt.title(\"1D Box Model Outputs\")\n\n    fig, ax = plt.subplots(nrows=2, ncols=2)\n    ax[0, 0].plot(T[NORTH_IDX], label='North')\n    ax[0, 1].plot(T[SOUTH_IDX], label='South')\n    ax[1, 0].plot(T[LOW_IDX], label='Low')\n    ax[1, 1].plot(T[DEEP_IDX], label='Deep')\n    ax[0, 0].legend()\n    ax[0, 1].legend()\n    ax[1, 0].legend()\n    ax[1, 1].legend()\n    plt.suptitle(\"Temperature in the 4 different boxes\")\n    plt.tight_layout()\n\n    fig1, ax1 = plt.subplots(nrows=2, ncols=2)\n    ax1[0, 0].plot(S[NORTH_IDX], label='North')\n    ax1[0, 1].plot(S[SOUTH_IDX], label='South')\n    ax1[1, 0].plot(S[LOW_IDX], label='Low')\n    ax1[1, 1].plot(S[DEEP_IDX], label='Deep')\n    ax1[0, 0].legend()\n    ax1[0, 1].legend()\n    ax1[1, 0].legend()\n    ax1[1, 1].legend()\n    plt.suptitle(\"Salinity in the 4 different boxes\")\n    plt.tight_layout()\n\n    fig2, ax2 = plt.subplots(nrows=2, ncols=2)\n    ax2[0, 0].plot(sigma0[NORTH_IDX], label='North')\n    ax2[0, 1].plot(sigma0[SOUTH_IDX], label='South')\n    ax2[1, 0].plot(sigma0[LOW_IDX], label='Low')\n    ax2[1, 1].plot(sigma0[DEEP_IDX], label='Deep')\n    ax2[0, 0].legend()\n    ax2[0, 1].legend()\n    ax2[1, 0].legend()\n    ax2[1, 1].legend()\n    plt.suptitle(\"Density in the 4 different boxes\")\n    plt.tight_layout()\n    plt.show(block=False)\n\n    # Consider an example of some data collection\n    Fwn_values_to_test = [10000, 50000, 100000, 500000, 1000000]\n    alternate_north_starting_temp = 4.0\n\n    box_dims = BoxModelBoxDimensions()\n    params = BoxModelParameters()\n    time_step = BoxModelTimeStep()\n    init = BoxModelInitConditions(T_north0=alternate_north_starting_temp)\n\n    # Collect the data... (should take a few seconds)\n    print(f\"Generating data for alternate parameter settings: T_north={alternate_north_starting_temp}\")\n    start_time = time.time()\n    results = []\n    for fwn in Fwn_values_to_test:\n        print(f\"Fwn={fwn}\")\n        params.Fwn = fwn\n        results.append(box_model(box_dims, init, params, time_step))\n    time_to_collect_data = time.time() - start_time\n    print(f\"Total time to collect data: {time_to_collect_data} seconds\")\n\n    # Let's look at the difference in M_n for each run\n    print(\"Plotting results...\")\n    plt.figure()\n    for i in range(len(Fwn_values_to_test)):\n        plt.plot(results[i].M_n, label=f\"Fwn={Fwn_values_to_test[i]}\")\n    plt.title(f\"M_n for different Northern Fluxes and T_north0={alternate_north_starting_temp}\")\n    plt.legend()\n    plt.show()  # suspends script until plot windows are closed\n    print(\"Done\")\n\n\nif __name__ == \"__main__\":\n    main()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}