{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "f7d9993f",
      "metadata": {},
      "source": [
        "---\n",
        "title: \"QUICK-PDE - una función Qiskit de ColibriTD\"\n",
        "description: \"La función QUICK-PDE resuelve ecuaciones diferenciales parciales específicas del dominio utilizando un algoritmo H-DES e ColibriTD's, que puede resolver problemas multifísicos complejos.\"\n",
        "---\n",
        "\n",
        "{/* cspell:ignore CMAES, Hypoelastic, edgecolor, royalblue, rstride, cstride, colibritd, xlabel, ylabel, zlabel, Jaffali, Pressureless, Colorplot, viridis, fontsize, fontweight */}\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2f87f5f0",
      "metadata": {},
      "source": [
        "<span id=\"quick-pde-a-qiskit-function-by-colibritd\" />\n",
        "\n",
        "# QUICK-PDE: Una función Qiskit de ColibriTD\n",
        "\n",
        "*Consulte la [referencia de la API](/docs/api/functions/colibritd-pde)*\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "9cd91354",
      "metadata": {
        "tags": [
          "version-info"
        ]
      },
      "source": [
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "01701579",
      "metadata": {},
      "source": [
        "<Admonition type=\"note\">\n",
        "  Qiskit Functions es una función experimental disponible para los usuarios de IBM Quantum® Premium Plan, Flex Plan y On-Prem (a través de IBM Quantum Platform API). Se trata de versiones preliminares sujetas a cambios.\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dde95705",
      "metadata": {},
      "source": [
        "<span id=\"overview\" />\n",
        "\n",
        "## Visión general\n",
        "\n",
        "El solucionador de ecuaciones diferenciales parciales (PDE) que aquí se presenta forma parte de nuestra plataforma Quantum Innovative Computing Kit (QUICK) (QUICK-PDE) y se incluye como una función Qiskit. Con la función QUICK-PDE, puede resolver ecuaciones diferenciales parciales específicas de dominio en  las QPU de IBM Quantum. Esta función se basa en el algoritmo descrito en [el documento descriptivo de H-DES](https://arxiv.org/abs/2410.01130) de ColibriTD's. Este algoritmo puede resolver problemas multifísicos complejos, comenzando por la dinámica de fluidos computacional (CFD) y la deformación de materiales (MD), y pronto se añadirán otros casos de uso.\n",
        "\n",
        "Para abordar las ecuaciones diferenciales, las soluciones de prueba se codifican como combinaciones lineales de funciones ortogonales (típicamente polinomios de Chebyshev, y más concretamente $2^n$ de ellos donde $n$ es el número de qubits que codifican su función), parametrizadas por los ángulos de un Circuito Cuántico Variable (VQC). El ansatz genera un estado que codifica la función, que se evalúa mediante observables cuyas combinaciones permiten evaluar la función en todos los puntos. A continuación, puede evaluar la función de pérdida en la que se codifican las ecuaciones diferenciales y ajustar los ángulos en un bucle híbrido, como se muestra a continuación. Las soluciones de prueba se acercan gradualmente a las soluciones reales hasta que se alcanza un resultado satisfactorio.\n",
        "\n",
        "![Flujo de trabajo de la función QUICK-PDE](https://quantum.cloud.ibm.com/docs/images/guides/colibritd-equation-solver/diagram.svg)\n",
        "\n",
        "Además de este bucle híbrido, también se pueden encadenar distintos optimizadores. Esto es útil cuando se desea un optimizador global para encontrar un buen conjunto de ángulos, y luego un optimizador más afinado para seguir un gradiente al mejor conjunto de ángulos vecinos. En el caso de la dinámica de fluidos computacional (CFD), la secuencia de optimización predeterminada produce los mejores resultados, pero en el caso de la deformación de materiales (MD), aunque la predeterminada proporciona buenos resultados, puede configurarla aún más para obtener ventajas específicas del problema.\n",
        "\n",
        "Observa que para cada variable de la función, especificamos el número de qubits (con el que puedes jugar). Al apilar 10 circuitos idénticos y evaluar los 10 observables idénticos en diferentes qubits a lo largo de un gran circuito, se puede mitigar el ruido dentro del proceso de optimización CMA, confiando en el método del aprendiz de ruido, y reducir significativamente el número de disparos necesarios.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "be28949c",
      "metadata": {},
      "source": [
        "<span id=\"computational-fluid-dynamics\" />\n",
        "\n",
        "### Dinámica de fluidos computacional\n",
        "\n",
        "**La ecuación de Burgers para** fluidos no viscosos modela el flujo de dichos fluidos de la siguiente manera:\n",
        "\n",
        "$\\frac{\\partial u}{\\partial t} + u\\frac{\\partial u}{\\partial x} = 0,$\n",
        "\n",
        "$u$ representa el campo de velocidades del fluido. Este caso de uso tiene una condición límite temporal: puedes seleccionar la condición inicial y, a continuación, dejar que el sistema se estabilice. Actualmente, las únicas condiciones iniciales aceptadas son funciones lineales: $ax + b$. La solución analítica es:\n",
        "\n",
        "$u(t, x) = \\frac{ax + b}{at + 1}.$\n",
        "\n",
        "**Las ecuaciones de Euler sin presión** modelan el flujo de un fluido compresible e inviscido con amortiguamiento de la siguiente manera:\n",
        "\n",
        "$\\frac{\\partial g}{\\partial t} + u\\frac{\\partial g}{\\partial x} + g\\frac{\\partial u}{\\partial x} = 0,$\n",
        "\n",
        "$u\\frac{\\partial g}{\\partial t} + g\\frac{\\partial u}{\\partial t} + u^2\\frac{\\partial g}{\\partial x} + 2gu\\frac{\\partial u}{\\partial x} + \\frac{\\mu}{(1+t)^{\\lambda}} g u = 0,$\n",
        "\n",
        "$g$ representa el campo de densidad, $u$ el campo de velocidad y $\\mu$ un coeficiente de amortiguación. En nuestra formulación, establecemos que $\\lambda = 1$, por lo que no se utilizará como parámetro en lo que sigue. Este caso de uso tiene condiciones de contorno temporales: $g(0, x) = e^{-x}$ y $u(0, x) = x$. La solución analítica es:\n",
        "\n",
        "$g(t, x) = \\frac{1-\\mu}{(1+t)^{1-\\mu} - \\mu} \\exp\\!\\left(\\frac{(\\mu-1)\\, x}{(1+t)^{1-\\mu} - \\mu}\\right),$\n",
        "\n",
        "$u(t, x) = \\frac{(1-\\mu)\\, x}{\\left((1+t)^{1-\\mu} - \\mu\\right)(1+t)^{\\mu}}.$\n",
        "\n",
        "Los argumentos de las ecuaciones diferenciales de CFD están en una rejilla fija, como sigue:\n",
        "\n",
        "* $t$ está comprendida entre 0 y 0.95, con 41 puntos de muestreo. $x$ está comprendida entre 0 y 0.95, con 41 puntos de muestreo.\n",
        "\n",
        "<span id=\"material-deformation\" />\n",
        "\n",
        "### Deformación del material\n",
        "\n",
        "Este caso de uso se centra en **la deformación hipoelástica mediante un ensayo de tracción unidimensional**, en el que se aplica una fuerza de tracción en un extremo de una barra fijada en el espacio. Describimos el problema de la siguiente manera:\n",
        "\n",
        "$u' - \\frac{\\sigma}{3K} - \\frac{2}{\\sqrt{3}}\\epsilon_0\\left(\\frac{\\sigma'}{\\sigma_0\\sqrt{3}}\\right)^n = 0,$\n",
        "\n",
        "$\\sigma' - b = 0,$\n",
        "\n",
        "$K$ representa el módulo de compresibilidad del material sometido a estiramiento, $n$ el exponente de una ley de potencia, $b$ la fuerza por unidad de masa, $\\epsilon_0$ el límite de tensión proporcional, $\\sigma_0$ el límite de deformación proporcional, $u$ la función de tensión y $\\sigma$ la función de deformación. La solución analítica es:\n",
        "\n",
        "$\\sigma(x) = \\sigma_0 - bx,$\n",
        "\n",
        "$u(x) = -\\frac{3^{-(3+n)/2}}{2bK(1+n)\\,\\sigma_0^{n}}\\Biggl[3^{(1+n)/2}b^2\\sigma_0^n(1+n)x^2 - 2\\cdot 3^{(1+n)/2}b\\sigma_0^n(1+n)\\sigma_0 x - 12\\epsilon_0 K\\sigma_0^{1+n}$\n",
        "$- 12b\\epsilon_0 K\\sigma_0^n x\\left(\\frac{-bx+\\sigma_0}{\\sigma_0}\\right)^n + 12\\epsilon_0 K\\sigma_0^{n+1}\\left(\\frac{-bx+\\sigma_0}{\\sigma_0}\\right)^n - 12\\epsilon_0 K \\sigma_0^{1+n}\\Biggr],$\n",
        "\n",
        "donde $\\sigma_0 = g(0)$ es la condición de contorno relativa a la deformación en $x=0$.\n",
        "\n",
        "La barra considerada es de longitud unitaria. Este caso de uso tiene una condición límite para la tensión superficial $t$, o la cantidad de trabajo necesaria para estirar la barra.\n",
        "\n",
        "Los argumentos de las ecuaciones diferenciales de MD están en una rejilla fija, como sigue:\n",
        "\n",
        "* $x$ está comprendido entre 0 y 1 y tiene 30 puntos de muestreo.\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "b34fe075",
      "metadata": {},
      "source": [
        "<span id=\"benchmarks\" />\n",
        "\n",
        "## Referencias comparativas\n",
        "\n",
        "El siguiente cuadro presenta estadísticas sobre varias ejecuciones de nuestra función.\n",
        "\n",
        "| Ejemplo                            | Número de qubits | Inicialización        | Error     | Tiempo total (min.) | Tiempo de ejecución (min) |\n",
        "| ---------------------------------- | ---------------- | --------------------- | --------- | ------------------- | ------------------------- |\n",
        "| Ecuación viscosa de Burgers        | 50               | `PHYSICALLY_INFORMED` | $10^{-2}$ | 65                  | 25                        |\n",
        "| Ecuaciones de Euler sin presión    | 73               | `PHYSICALLY_INFORMED` | $10^{-2}$ | 48                  | 34                        |\n",
        "| Prueba de tracción hipoelástica 1D | 18               | `RANDOM`              | $10^{-2}$ | 123                 | 100                       |\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "73390a19",
      "metadata": {},
      "source": [
        "<span id=\"get-started\" />\n",
        "\n",
        "## Cómo empezar\n",
        "\n",
        "Rellena el [formulario para solicitar acceso a la función QUICK-PDE](https://forms.cloud.microsoft/e/3Wi9cbjQPK). A continuación, suponiendo que ya hayas [guardado tu cuenta](/docs/guides/functions-get-started#install-qiskit-functions-catalog-client) en tu entorno local, selecciona la función de la siguiente manera:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "95a715d2",
      "metadata": {},
      "outputs": [],
      "source": [
        "from qiskit_ibm_catalog import QiskitFunctionsCatalog\n",
        "\n",
        "catalog = QiskitFunctionsCatalog(\n",
        "    channel=\"ibm_cloud / ibm_quantum_platform\",\n",
        "    instance=\"USER_CRN / HGP\",\n",
        "    token=\"USER_API_KEY / IQP_API_TOKEN\",\n",
        ")\n",
        "\n",
        "catalog = QiskitFunctionsCatalog(channel=\"ibm_quantum_platform\")\n",
        "\n",
        "# Verify that you have access to the function\n",
        "catalog.list()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "4ec04623",
      "metadata": {},
      "outputs": [],
      "source": [
        "quick = catalog.load(\"colibritd/quick-pde\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e8837f5f",
      "metadata": {},
      "source": [
        "<span id=\"examples\" />\n",
        "\n",
        "## Ejemplos\n",
        "\n",
        "Para empezar, prueba uno de los siguientes ejemplos:\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "446ac943",
      "metadata": {},
      "source": [
        "<span id=\"inviscid-burgers-equation-cfd\" />\n",
        "\n",
        "### Ecuación de Inviscid Burgers (CFD)\n",
        "\n",
        "En el caso de la ecuación de Burgers, cuando las condiciones iniciales se establecen en $u(0,x) = x$, los resultados son los siguientes:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "d56e1440",
      "metadata": {},
      "outputs": [],
      "source": [
        "# launch the simulation with initial conditions u(0,x) = a*x + b\n",
        "job = quick.run(\n",
        "    use_case=\"CFD_BURGER\", physical_parameters={\"a\": 1.0, \"b\": 0.0}\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "03998691",
      "metadata": {},
      "source": [
        "Comprueba [el estado](/docs/guides/functions-get-started#check-job-status) de tu carga de trabajo de Qiskit Function o obtén [los resultados](/docs/guides/functions-get-started#retrieve-results) de la siguiente manera:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "856fe992",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Print the ID so you can use it later, if necessary\n",
        "print(job.job_id)\n",
        "print(job.status())\n",
        "solution = job.result()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c42aba9b",
      "metadata": {},
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "\n",
        "def plot_result_3d(result):\n",
        "    fig = plt.figure()\n",
        "    ax = fig.add_subplot(projection=\"3d\")\n",
        "\n",
        "    t, x = np.meshgrid(result[\"samples\"][\"t\"], result[\"samples\"][\"x\"])\n",
        "\n",
        "    ax.plot_surface(\n",
        "        t,\n",
        "        x,\n",
        "        result[\"functions\"][\"u\"],\n",
        "        edgecolor=\"royalblue\",\n",
        "        lw=0.25,\n",
        "        rstride=26,\n",
        "        cstride=26,\n",
        "        alpha=0.3,\n",
        "    )\n",
        "    ax.scatter(t, x, result[\"functions\"][\"u\"], marker=\".\")\n",
        "    ax.set(xlabel=\"t\", ylabel=\"x\", zlabel=\"u(t,x)\")\n",
        "\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "# Call\n",
        "plot_result_3d(solution)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "4408d52e",
      "metadata": {},
      "source": [
        "<span id=\"pressureless-eulers-equation-cfd\" />\n",
        "\n",
        "### Ecuación de Euler sin presión (CFD)\n",
        "\n",
        "En el caso de la ecuación de Euler, cuando las condiciones iniciales se establecen en $g(0, x) = e^{-x}$ y $u(0, x) = x$, para un $\\mu$ dado (en este caso, $\\mu = 0.1$ ) y un $\\lambda = 1$, los resultados son los siguientes:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e0412513",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Launches the solving for an arbitrary mu\n",
        "job = quick.run(use_case=\"CFD_EULER\", physical_parameters={\"mu\": 0.1})\n",
        "\n",
        "solution = job.result()\n",
        "\n",
        "\n",
        "# Colorplot function\n",
        "def plot_result_2d(result):\n",
        "    fig, axes = plt.subplots(1, 2, figsize=(14, 5))\n",
        "\n",
        "    configs = {\n",
        "        \"g\": {\"cmap\": \"viridis\", \"title\": \"g(t, x)\"},\n",
        "        \"u\": {\"cmap\": \"plasma\", \"title\": \"u(t, x)\"},\n",
        "    }\n",
        "\n",
        "    t = result[\"samples\"][\"t\"]\n",
        "    x = result[\"samples\"][\"x\"]\n",
        "\n",
        "    for ax, (field, cfg) in zip(axes, configs.items()):\n",
        "        v = result[\"functions\"][field]\n",
        "\n",
        "        im = ax.contourf(t, x, v, levels=50, cmap=cfg[\"cmap\"])\n",
        "        fig.colorbar(im, ax=ax, label=cfg[\"title\"])\n",
        "\n",
        "        ax.set_xlabel(\"t\")\n",
        "        ax.set_ylabel(\"x\")\n",
        "        ax.set_title(cfg[\"title\"], fontsize=13, fontweight=\"bold\")\n",
        "\n",
        "    plt.tight_layout()\n",
        "    plt.show()\n",
        "\n",
        "\n",
        "plot_result_2d(solution)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "dbbd4509",
      "metadata": {},
      "source": [
        "<span id=\"material-deformation\" />\n",
        "\n",
        "### Deformación del material\n",
        "\n",
        "El caso de uso de la deformación del material requiere los parámetros físicos de su material y la fuerza aplicada, como se indica a continuación:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a568e325",
      "metadata": {},
      "outputs": [],
      "source": [
        "# Select the properties of your material\n",
        "job = quick.run(\n",
        "    use_case=\"MD\",\n",
        "    physical_parameters={\n",
        "        \"t\": 12.0,\n",
        "        \"K\": 100.0,\n",
        "        \"n\": 4.0,\n",
        "        \"b\": 10.0,\n",
        "        \"epsilon_0\": 0.1,\n",
        "        \"sigma_0\": 5.0,\n",
        "    },\n",
        ")\n",
        "\n",
        "# Plot the result\n",
        "solution = job.result()\n",
        "\n",
        "_ = plt.figure()\n",
        "stress_plot = plt.subplot(211)\n",
        "plt.plot(solution[\"samples\"][\"x\"], solution[\"functions\"][\"u\"])\n",
        "strain_plot = plt.subplot(212)\n",
        "plt.plot(solution[\"samples\"][\"x\"], solution[\"functions\"][\"sigma\"])\n",
        "\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f1cfa869",
      "metadata": {},
      "source": [
        "A continuación se muestra un ejemplo de cómo obtener el valor de la función para un conjunto concreto de coordenadas:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "c5193114",
      "metadata": {},
      "outputs": [],
      "source": [
        "# u(t=0.2, x=0.7) == 2\n",
        "assert solution[\"samples\"][\"t\"][1] == 0.2\n",
        "assert solution[\"samples\"][\"x\"][2] == 0.7\n",
        "assert solution[\"functions\"][\"u\"][1, 2] == 2"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "04236c83",
      "metadata": {},
      "source": [
        "<span id=\"fetch-error-messages\" />\n",
        "\n",
        "## Obtener mensajes de error\n",
        "\n",
        "Si el estado de su carga de trabajo es `ERROR`, utilice `job.error_message()` para obtener el mensaje de error para ayudar a depurar, de la siguiente manera:\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "90c6de7c",
      "metadata": {},
      "outputs": [],
      "source": [
        "job = quick.run(use_case=\"MD\", physical_params={})\n",
        "\n",
        "print(job.error_message())\n",
        "\n",
        "\n",
        "# A wrapper can also be used for a more human readable version\n",
        "def pprint_error(job):\n",
        "    print(\"\".join(eval(job.error_message())[\"error\"]))\n",
        "\n",
        "\n",
        "print(\"___\")\n",
        "pprint_error(job)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e9ec2e67",
      "metadata": {},
      "source": [
        "<span id=\"get-support\" />\n",
        "\n",
        "## Obtener soporte\n",
        "\n",
        "Para obtener asistencia, póngase en contacto con [qiskit-function-support@colibritd.com](mailto:qiskit-function-support@colibritd.com).\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5a6a25c8",
      "metadata": {},
      "source": [
        "<span id=\"next-steps\" />\n",
        "\n",
        "## Próximos pasos\n",
        "\n",
        "<Admonition type=\"tip\" title=\"Recomendaciones\">\n",
        "  * Rellene el formulario para [solicitar acceso a la función QUICK-PDE](https://forms.cloud.microsoft/e/3Wi9cbjQPK).\n",
        "  * Consulta la [referencia](/docs/api/functions/colibritd-pde) de la API de esta función de Qiskit.\n",
        "  * Pruebe a modelar un fluido no viscoso fluyente utilizando QUICK-PDE en el [tutorial](/docs/tutorials/colibritd-pde).\n",
        "  * Revisión [Jaffali, H., et al. (2025).  H-DES: un solucionador híbrido cuántico-clásico de ecuaciones diferenciales. arXiv Preimpresión arXiv:2410.01130](https://arxiv.org/abs/2410.01130).\n",
        "</Admonition>\n",
        "\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "id": "a1b8767d",
      "source": "© IBM Corp., 2017-2026"
    }
  ],
  "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"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}