{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c1dfe1e9-c8da-4bdf-91f8-bfc20e7c424b",
   "metadata": {},
   "source": [
    "# Phases with Electrically Charged Species"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "da3a3b01-0a48-430c-922b-a4c8490ed1bf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-02-19T19:16:59.831990Z",
     "iopub.status.busy": "2022-02-19T19:16:59.831990Z",
     "iopub.status.idle": "2022-02-19T19:17:59.711282Z",
     "shell.execute_reply": "2022-02-19T19:17:59.711282Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 215628 characters]",
      "text/plain": [
       "<Figure size 2700x1800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "from pycalphad import Database, binplot\n",
    "import pycalphad.variables as v\n",
    "\n",
    "# Load database and choose the phases that will be considered\n",
    "dbf = Database('Fe-O.tdb')\n",
    "phases = sorted(dbf.phases.keys())\n",
    "\n",
    "# Create a matplotlib Figure object and get the active Axes\n",
    "fig = plt.figure(figsize=(9,6), dpi=300)\n",
    "axes = fig.gca()\n",
    "# Compute the phase diagram and plot it on the existing axes using the `plot_kwargs={'ax': axes}` keyword argument\n",
    "binplot(dbf, ['FE', 'O', 'VA'], phases, {v.X('O'):(0,1,0.01), v.T: (800, 2000, 10), v.P:101325, v.N: 1},\n",
    "        plot_kwargs={'ax': axes})\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "10f656ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pycalphad.mapping import StepStrategy, plot_step\n",
    "\n",
    "strategy = StepStrategy(dbf, ['FE', 'O', 'VA'], phases, {v.N: 1, v.T: (700, 2000, 10), v.P: 1e5, v.X('O'): 0.55})\n",
    "strategy.initialize()\n",
    "strategy.do_map()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1701f44a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Phase fractions vs T @ X(O) = 0.55')"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 179368 characters]",
      "text/plain": [
       "<Figure size 1920x1440 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(dpi=300)\n",
    "ax = fig.gca()\n",
    "plot_step(strategy, ax=ax)\n",
    "ax.set_title('Phase fractions vs T @ X(O) = 0.55')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "e36ddfb1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 78484 characters]",
      "text/plain": [
       "<Figure size 960x720 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from pycalphad import Model\n",
    "\n",
    "fig = plt.figure(dpi=150)\n",
    "ax = fig.add_subplot()\n",
    "\n",
    "def create_label(sf_idx, sf_sym):\n",
    "    # Note: This formatting assumes multiplicity of 1 for all species\n",
    "    species_constituents = ''.join(\n",
    "            ['{}'.format(el) for el, val in sorted(sf_sym.species.constituents.items(), key=lambda t: t[0])])\n",
    "    subl_idx = sf_sym.sublattice_index\n",
    "    charge = sf_sym.species.charge\n",
    "    if charge == 0:\n",
    "        charge = ''\n",
    "    elif charge > 0:\n",
    "        charge = str(charge)+'\\!+'\n",
    "    else:\n",
    "        charge = str(abs(charge))+'\\!-'\n",
    "    label_name = '$^{1}{0}^{{{2}}}$'.format(species_constituents, subl_idx, charge)\n",
    "    return label_name\n",
    "\n",
    "desired_phase = 'SPINEL'\n",
    "mod = Model(dbf, ['FE', 'O', 'VA'], desired_phase)\n",
    "\n",
    "for sf_idx, sf_sym in enumerate(mod.site_fractions):\n",
    "    data = strategy.get_data(v.T, sf_sym)['data'][desired_phase]\n",
    "    indices = data['y'] != 0\n",
    "    ax.plot(data['x'][indices]-273.15, data['y'][indices], label=create_label(sf_idx, sf_sym))\n",
    "    \n",
    "ax.legend(loc='center left', bbox_to_anchor=(1.01, 0.5))\n",
    "ax.set_xlabel('Temperature (Celsius)')\n",
    "ax.set_ylabel('Site Fraction')\n",
    "ax.set_title(f'{desired_phase} Constituent Distribution');"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3549e36c",
   "metadata": {},
   "source": [
    "Alternatively, phase fraction and site fractions can be computed and plotted through the equilibrium API."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "565bf2b1-6a8f-481b-9364-d7c14acc4ba2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-02-19T19:17:59.752683Z",
     "iopub.status.busy": "2022-02-19T19:17:59.751149Z",
     "iopub.status.idle": "2022-02-19T19:18:04.771602Z",
     "shell.execute_reply": "2022-02-19T19:18:04.771602Z"
    },
    "scrolled": true,
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pycalphad import equilibrium\n",
    "eq = equilibrium(dbf, ['FE', 'O', 'VA'], phases,\n",
    "                 {v.N: 1, v.T: (700, 2000, 10), v.P: 1e5, v.X('O'): 0.55})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "47092ac7-19f0-41f9-ab07-02e5ff33be08",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-02-19T19:18:04.811638Z",
     "iopub.status.busy": "2022-02-19T19:18:04.801188Z",
     "iopub.status.idle": "2022-02-19T19:18:05.151804Z",
     "shell.execute_reply": "2022-02-19T19:18:05.151804Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x1ca89dc73d0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 170436 characters]",
      "text/plain": [
       "<Figure size 1920x1440 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from pycalphad.plot.utils import phase_legend\n",
    "phases = sorted(set(eq.Phase.values.flatten()) - {''})\n",
    "\n",
    "fig = plt.figure(dpi=300)\n",
    "ax = fig.gca()\n",
    "phase_handles, phasemap = phase_legend(phases)\n",
    "ax.set_title('Phase fractions vs T @ X(O) = 0.55')\n",
    "ax.set_xlabel('Temperature (Celsius)')\n",
    "ax.set_ylabel('Phase Fraction')\n",
    "ax.set_ylim((0,1.1))\n",
    "ax.set_xlim((700-273.15, 2000-273.15))\n",
    "\n",
    "for name in phases:\n",
    "    ax.plot(np.squeeze(eq.T.broadcast_like(eq.NP)-273.15), np.squeeze(eq.NP.where(eq.Phase == name)),\n",
    "             color=phasemap[name], label=name)\n",
    "plt.gca().legend(phase_handles, phasemap, loc='upper center')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bd252708-d84a-4eef-b382-3722abcb5723",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2022-02-19T19:18:05.171259Z",
     "iopub.status.busy": "2022-02-19T19:18:05.161311Z",
     "iopub.status.idle": "2022-02-19T19:18:06.101645Z",
     "shell.execute_reply": "2022-02-19T19:18:06.101645Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 63060 characters]",
      "text/plain": [
       "<Figure size 960x720 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from pycalphad import Model\n",
    "fig = plt.figure(dpi=150)\n",
    "ax = fig.add_subplot()\n",
    "\n",
    "desired_phase = 'SPINEL'\n",
    "\n",
    "mod = Model(dbf, ['FE', 'O', 'VA'], desired_phase)\n",
    "\n",
    "# Plot site fractions by index and label them using the ._latex() feature of SymPy symbols\n",
    "for sf_idx, sf_sym in enumerate(mod.site_fractions):\n",
    "    masked_eq_res = eq.where(eq.Phase == desired_phase).isel(internal_dof=sf_idx)\n",
    "    # Note: This formatting assumes multiplicity of 1 for all species\n",
    "    species_constituents = ''.join(\n",
    "            ['{}'.format(el) for el, val in sorted(sf_sym.species.constituents.items(), key=lambda t: t[0])])\n",
    "    subl_idx = sf_sym.sublattice_index\n",
    "    charge = sf_sym.species.charge\n",
    "    if charge == 0:\n",
    "        charge = ''\n",
    "    elif charge > 0:\n",
    "        charge = str(charge)+'\\!+'\n",
    "    else:\n",
    "        charge = str(abs(charge))+'\\!-'\n",
    "    label_name = '$^{1}{0}^{{{2}}}$'.format(species_constituents, subl_idx, charge)\n",
    "    temperature_in_celsius = masked_eq_res.T.broadcast_like(masked_eq_res.Y).squeeze() - 273.15\n",
    "    ax.scatter(temperature_in_celsius, masked_eq_res.Y.squeeze(), s=2, label=label_name)\n",
    "\n",
    "ax.legend(loc='center left', bbox_to_anchor=(1.01, 0.5))\n",
    "ax.set_xlabel('Temperature (Celsius)')\n",
    "ax.set_ylabel('Site Fraction')\n",
    "ax.set_title(f'{desired_phase} Constituent Distribution');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6c04ecfb-57aa-4747-a9c7-69e0f45f772b",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
