{"id":556,"date":"2026-07-22T08:17:36","date_gmt":"2026-07-22T08:17:36","guid":{"rendered":"https:\/\/matforge.org\/?p=556","raw":"https:\/\/matforge.org\/?p=556"},"modified":"2026-07-22T08:17:36","modified_gmt":"2026-07-22T08:17:36","slug":"python-debugging-scientific-code-print-statements-profiling","status":"publish","type":"post","link":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/","title":{"rendered":"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles","raw":"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 12<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span><h2>Comida clave<\/h2>\n<ul>\n<li>Depuraci\u00f3n El c\u00f3digo cient\u00edfico de Python sigue una escala de escalamiento: <code>print<\/code>, <code>assert<\/code>, <code>pdb<\/code>, perfiles y pruebas.<\/li>\n<li>La mayor\u00eda de los errores cient\u00edficos son num\u00e9ricos, como los valores de NAN, las discrepancias en la forma de los arreglos, la p\u00e9rdida de precisi\u00f3n o los pasos de tiempo inestables.<\/li>\n<li><code>print()<\/code> Atrapa muchos errores para principiantes, pero las afirmaciones y los depuradores facilitan el aislamiento de las fallas.<\/li>\n<li>Un flujo de trabajo de depuraci\u00f3n cient\u00edfica confiable es: hacer que falle, a\u00edsle el problema, cambie una cosa, verifique y agregue una prueba.<\/li>\n<li>La creaci\u00f3n de perfiles puede revelar errores ocultos porque el c\u00f3digo lento es a menudo un signo de l\u00f3gica de matriz incorrecta, bucles accidentales o una asignaci\u00f3n excesiva.<\/li>\n<\/ul>\n<p>Depurar el c\u00f3digo cient\u00edfico Python es una de las habilidades m\u00e1s frustrantes que se pueden desarrollar. Escribe lo que deber\u00eda ser una simple simulaci\u00f3n de difusi\u00f3n de calor, el c\u00f3digo se ejecuta sin errores y la salida es completamente incorrecta.<\/p>\n<p>Sin choque. Sin rastreo. solo n\u00fameros incorrectos en silencio.<\/p>\n<p>Ese es el desaf\u00edo \u00fanico de la depuraci\u00f3n cient\u00edfica. Los insectos m\u00e1s peligrosos son a menudo los que no se estrellan en absoluto. Un n\u00famero incorrecto puede propagarse a trav\u00e9s de miles de iteraciones y producir un resultado que parece f\u00edsicamente plausible hasta que verifique la conservaci\u00f3n, la estabilidad o la convergencia.<\/p>\n<p>Esta gu\u00eda explica c\u00f3mo depurar el c\u00f3digo cient\u00edfico de Python en varios niveles: declaraciones de impresi\u00f3n, registro, aserciones, depuraci\u00f3n interactiva, perfiles y pruebas de regresi\u00f3n.<\/p>\n<p>Ya sea que est\u00e9 ejecutando una primera simulaci\u00f3n FIPY o depurando una canalizaci\u00f3n de investigaci\u00f3n de producci\u00f3n, este flujo de trabajo le brinda una estructura pr\u00e1ctica a seguir.<\/p>\n<h2>\u00bfQu\u00e9 tiene de diferente la depuraci\u00f3n del c\u00f3digo cient\u00edfico?<\/h2>\n<p>La depuraci\u00f3n cient\u00edfica es diferente de la depuraci\u00f3n de una aplicaci\u00f3n web, API o canalizaci\u00f3n de datos ordinaria.<\/p>\n<p>Los n\u00fameros pueden mentir. Una aplicaci\u00f3n web a menudo falla visiblemente: un bot\u00f3n no funciona, una API devuelve un error o falla una consulta de base de datos. El c\u00f3digo cient\u00edfico puede funcionar perfectamente y a\u00fan as\u00ed producir resultados incorrectos. Una concentraci\u00f3n negativa, un campo de energ\u00eda explosiva o una NAN oculta solo puede aparecer si lo comprueba directamente.<\/p>\n<p>La correcci\u00f3n se define por la f\u00edsica, no solo por la sintaxis. Un programa de Python que se ejecuta es sint\u00e1cticamente v\u00e1lido. Un programa cient\u00edfico solo es cre\u00edble si coincide con las soluciones conocidas, conserva las cantidades esperadas, respeta las condiciones de los l\u00edmites y converge bajo el refinamiento.<\/p>\n<p>Los rastros de pila a menudo apuntan a n\u00fameros internos numpy, scipy o fip. El error real puede estar en su configuraci\u00f3n, pero el mensaje de error puede aparecer en lo m\u00e1s profundo de una biblioteca. Es por eso que la depuraci\u00f3n cient\u00edfica necesita un proceso estructurado, no solo la lectura de rastreo.<\/p>\n<h2>El flujo de trabajo de depuraci\u00f3n: un modelo mental de cinco pasos<\/h2>\n<p>Un \u00fatil flujo de trabajo de depuraci\u00f3n para c\u00f3digo cient\u00edfico sigue cinco pasos.<\/p>\n<h3>Paso 1: Haz que falle<\/h3>\n<p>Su primer trabajo es crear un caso de prueba que falla cada vez. En el c\u00f3digo cient\u00edfico, esto generalmente significa construir un ejemplo reproducible m\u00ednimo que produce un resultado incorrecto.<\/p>\n<p>No necesita la simulaci\u00f3n completa. Necesita el c\u00f3digo m\u00e1s peque\u00f1o que demuestre el error.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\n# Full simulation may be hundreds of lines.\n# Start with the smallest failing update step.\n\nphi = np.ones((10, 10))\nphi[:] = 0.5\n\ngradient = np.gradient(phi)[0]\nphi_new = phi - 0.1 * gradient\n\nprint(f\"min(phi_new) = {np.min(phi_new)}\")\nprint(f\"max(phi_new) = {np.max(phi_new)}\")\n<\/code><\/pre>\n<p>Al aislar el paso de actualizaci\u00f3n, crea un caso reproducible. Esta es la base de cada paso de depuraci\u00f3n posterior.<\/p>\n<h3>Paso 2: Dividir y conquistar<\/h3>\n<p>Una vez que tengas un caso fallido, a\u00edslalo m\u00e1s. Encuentre el m\u00f3dulo, funci\u00f3n, l\u00ednea o t\u00e9rmino de f\u00edsica responsable de la falla.<\/p>\n<p>Para el c\u00f3digo de simulaci\u00f3n, una t\u00e1ctica \u00fatil es probar cada t\u00e9rmino de f\u00edsica por separado. Si su modelo combina difusi\u00f3n, reacci\u00f3n y advecci\u00f3n, pruebe cada uno solo antes de depurar el sistema acoplado.<\/p>\n<pre><code class=\"language-python\">solution_diffusion = solve_diffusion_only(initial_conditions, dt)\nassert np.all(solution_diffusion &gt;= 0), \"Diffusion produced negative values\"\n\nsolution_reaction = solve_reaction_only(initial_conditions, dt)\nassert np.all(solution_reaction &gt;= 0), \"Reaction produced negative values\"\n\nsolution_coupled = solve_coupled(initial_conditions, dt)\n<\/code><\/pre>\n<p>Esto reduce el espacio de b\u00fasqueda. En lugar de depurar toda la simulaci\u00f3n, depura un t\u00e9rmino o un mecanismo de acoplamiento.<\/p>\n<h3>Paso 3: Cambiar una cosa a la vez<\/h3>\n<p>La depuraci\u00f3n cient\u00edfica se vuelve confusa cuando cambias varias variables a la vez. Si cambia el paso de tiempo, las condiciones de los l\u00edmites, la tolerancia al solucionador y la condici\u00f3n inicial juntos, no puede saber qu\u00e9 cambio importaba.<\/p>\n<p>Cambiar un par\u00e1metro. correr comparar documento.<\/p>\n<p>Utilice el control de versiones para realizar un seguimiento de los cambios. Incluso las confirmaciones simples como \u00abDT cambiadas de 0.01 a 0.001\u00bb pueden ahorrar horas despu\u00e9s.<\/p>\n<h3>Paso 4: Usa el depurador<\/h3>\n<p>Cuando las impresiones y las aserciones no sean suficientes, use <code>pdb<\/code>, <code>ipdb<\/code> o un depurador IDE. Un depurador le permite pausar la ejecuci\u00f3n, inspeccionar variables, pasar a trav\u00e9s del c\u00f3digo y verificar por qu\u00e9 cambi\u00f3 un valor.<\/p>\n<h3>Paso 5: agregar a la suite de prueba<\/h3>\n<p>Despu\u00e9s de corregir un error, agregue una prueba que lo habr\u00eda detectado. Esto evita que el mismo error regrese m\u00e1s tarde.<\/p>\n<pre><code class=\"language-python\">def test_no_negative_phases():\n    \"\"\"Verify phase field stays non-negative after diffusion.\"\"\"\n    phi = np.ones((10, 10))\n    phi = diffusion_step(phi, dt=0.01)\n    assert np.min(phi) &gt;= 0, f\"Got min value {np.min(phi)}\"\n<\/code><\/pre>\n<p>El flujo de trabajo es simple: aislar, dividir, cambiar una cosa, depurar y probar. El resto de esta gu\u00eda explica qu\u00e9 herramientas usar en cada nivel.<\/p>\n<h2>Nivel 1: Imprimir declaraciones y registro<\/h2>\n<p><code>print()<\/code> sigue siendo \u00fatil. Es la herramienta de depuraci\u00f3n m\u00e1s simple y atrapa muchos errores tempranos. La clave es usarlo con estructura.<\/p>\n<h3>El problema con las malas impresiones<\/h3>\n<p>Un error principiante com\u00fan es imprimir valores sin contexto.<\/p>\n<pre><code class=\"language-python\">for i in range(100):\n    print(phi[i])\n<\/code><\/pre>\n<p>Despu\u00e9s de algunas iteraciones, tiene muchos n\u00fameros sin un significado claro. No sabe qu\u00e9 variable, paso de tiempo o condici\u00f3n produjo cada l\u00ednea.<\/p>\n<h3>La forma correcta: impresiones estructuradas<\/h3>\n<p>Etiqueta todo. Incluya el paso de tiempo, el nombre de la variable, el m\u00ednimo, el m\u00e1ximo y cualquier cantidad conservada que le interese.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\nprint(\n    f\"[t={t:06.4f}] \"\n    f\"min(phi)={np.min(phi):.6f}, \"\n    f\"max(phi)={np.max(phi):.6f}\"\n)\n\nprint(\n    f\"[t={t:06.4f}] \"\n    f\"energy={np.sum(phi * phi):.6f}, \"\n    f\"mass={np.sum(phi):.6f}\"\n)\n<\/code><\/pre>\n<p>Esta salida es f\u00e1cil de escanear:<\/p>\n<pre><code>[t=0.0010] min(phi)=0.000000, max(phi)=1.000000\n[t=0.0010] energy=0.850000, mass=1.000000\n[t=0.0020] min(phi)=0.000000, max(phi)=1.023456\n[t=0.0020] energy=0.873456, mass=1.012345\n<\/code><\/pre>\n<p>Puede ver inmediatamente que el valor m\u00e1ximo se elev\u00f3 por encima de 1.0 y la masa cambi\u00f3. Esas son pistas \u00fatiles.<\/p>\n<h3>Registrar vs declaraciones de impresi\u00f3n<\/h3>\n<p>Para una depuraci\u00f3n seria, use el m\u00f3dulo <code>logging<\/code> de Python en lugar de RAW <code>print()<\/code>.<\/p>\n<pre><code class=\"language-python\">import logging\n\nlogging.basicConfig(\n    level=logging.DEBUG,\n    format=\"%(levelname)s: %(message)s\"\n)\n\nlogger = logging.getLogger(__name__)\n\nlogger.debug(\"Running diffusion step at t=%f, dt=%f\", t, dt)\nlogger.warning(\"Energy increased by %.5f\", energy_change)\n<\/code><\/pre>\n<p>El registro tiene varias ventajas:<\/p>\n<ul>\n<li>niveles como <code>DEBUG<\/code>, <code>WARNING<\/code> y <code>ERROR<\/code>.<\/li>\n<li>Marcas de tiempo opcionales y salida de archivo.<\/li>\n<li>F\u00e1cil activaci\u00f3n o desactivaci\u00f3n sin eliminar el c\u00f3digo de depuraci\u00f3n.<\/li>\n<li>Diagn\u00f3sticos m\u00e1s limpios durante largos recorridos de simulaci\u00f3n.<\/li>\n<\/ul>\n<p>Una regla pr\u00e1ctica es usar <code>print()<\/code> para scripts exploratorios r\u00e1pidos y <code>logging<\/code> para c\u00f3digo de simulaci\u00f3n reutilizable o de producci\u00f3n.<\/p>\n<h2>Nivel 2: Aserciones y controles de cordura<\/h2>\n<p>Las afirmaciones son como declaraciones impresas que se niegan a permanecer en silencio. Producen un error cuando se viola una suposici\u00f3n.<\/p>\n<h3>El patr\u00f3n: suposiciones primero<\/h3>\n<p>El patr\u00f3n m\u00e1s \u00fatil es verificar las entradas, ejecutar el solucionador y verificar las salidas.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\ndef solve_diffusion(phi, dt, diffusion_coeff):\n    # Preconditions\n    assert np.all(phi &gt;= 0), f\"Negative phase: {np.min(phi)}\"\n    assert np.all(phi &lt;= 1), f\"Phase &gt; 1: {np.max(phi)}\"\n    assert np.isfinite(phi).all(), \"Non-finite input values detected\"\n    \n    # Solver step\n    phi_new = apply_diffusion(phi, dt, diffusion_coeff)\n    \n    # Postconditions\n    assert np.isfinite(phi_new).all(), \"Solver produced NaN or Inf\"\n    assert np.all(phi_new &gt;= 0), f\"Negative output: {np.min(phi_new)}\"\n    \n    return phi_new\n<\/code><\/pre>\n<p>Esto convierte la falla num\u00e9rica silenciosa en un error claro con la ubicaci\u00f3n y el contexto.<\/p>\n<h3>La filosof\u00eda de la afirmaci\u00f3n<\/h3>\n<p>Las afirmaciones no se tratan solo de atrapar errores. Fijan errores.<\/p>\n<p>Una afirmaci\u00f3n que falla cerca del comienzo de un solucionador le dice d\u00f3nde se rompi\u00f3 la suposici\u00f3n. Una nana que aparece cientos de l\u00edneas m\u00e1s tarde te dice mucho menos.<\/p>\n<p>Los lugares \u00fatiles para las afirmaciones incluyen:<\/p>\n<ul>\n<li>Llamadas antes y despu\u00e9s del solucionador.<\/li>\n<li>en los l\u00edmites del m\u00f3dulo donde se intercambian los datos.<\/li>\n<li>Despu\u00e9s de operaciones de malla como refinamiento, reajuste o engrosamiento.<\/li>\n<li>despu\u00e9s de aplicar las condiciones de contorno.<\/li>\n<\/ul>\n<h3>Una advertencia sobre las afirmaciones<\/h3>\n<p>No use las afirmaciones en exceso en bucles internos caros a menos que las necesite. Pueden agregar sobrecarga de tiempo de ejecuci\u00f3n y hacer que la depuraci\u00f3n sea ruidosa.<\/p>\n<p>Use aserciones para invariantes y condiciones previas: condiciones que nunca deben violarse si el c\u00f3digo es correcto.<\/p>\n<h2>Nivel 3: El depurador de Python<\/h2>\n<p>Cuando las declaraciones de impresi\u00f3n no sean suficientes, use un depurador interactivo. Un depurador le permite pausar el programa, inspeccionar el estado y pasar por la l\u00f3gica.<\/p>\n<h3>La herramienta cl\u00e1sica: PDB<\/h3>\n<p><code>pdb<\/code> es el depurador incorporado de Python. Est\u00e1 disponible en cada instalaci\u00f3n de Python.<\/p>\n<p>En ipython, puede usar la depuraci\u00f3n post-mortem despu\u00e9s de un error:<\/p>\n<pre><code class=\"language-python\">In [1]: %run simulation.py\n\nIn [2]: %debug\n<\/code><\/pre>\n<p>Esto lo deja caer en el depurador en el punto de falla.<\/p>\n<p>Para los scripts de l\u00ednea de comandos, inicie el script con el depurador:<\/p>\n<pre><code class=\"language-bash\">python -m pdb simulation.py\n<\/code><\/pre>\n<p>Los comandos \u00fatiles incluyen:<\/p>\n<ul>\n<li><code>c<\/code>: Contin\u00fae la ejecuci\u00f3n.<\/li>\n<li><code>n<\/code>: Mover a la siguiente l\u00ednea.<\/li>\n<li><code>s<\/code>: Paso a una llamada de funci\u00f3n.<\/li>\n<li><code>b<\/code>: Establezca un punto de interrupci\u00f3n.<\/li>\n<li><code>p variable_name<\/code>: imprime una variable.<\/li>\n<li><code>q<\/code>: salga del depurador.<\/li>\n<\/ul>\n<p>Tambi\u00e9n puede insertar un punto de interrupci\u00f3n directamente en el c\u00f3digo:<\/p>\n<pre><code class=\"language-python\">def solve_phase_field(phi, dt):\n    import pdb\n    pdb.set_trace()\n    \n    phi_new = update_phase_field(phi, dt)\n    return phi_new\n<\/code><\/pre>\n<h3>Depuraci\u00f3n de IPDB e IPython<\/h3>\n<p><code>ipdb<\/code> es una versi\u00f3n mejorada de <code>pdb<\/code>. Proporciona la finalizaci\u00f3n de la pesta\u00f1a, un mejor formato y una experiencia interactiva m\u00e1s c\u00f3moda.<\/p>\n<pre><code class=\"language-bash\">pip install ipdb\n<\/code><\/pre>\n<pre><code class=\"language-python\">import ipdb\nipdb.set_trace()\n<\/code><\/pre>\n<p>Para los usuarios de IPython, <code>%debug<\/code> suele ser la opci\u00f3n m\u00e1s r\u00e1pida despu\u00e9s de una excepci\u00f3n.<\/p>\n<h3>Depuradores IDE<\/h3>\n<p>PyCharm, VS Code y Spyder incluyen depuradores gr\u00e1ficos. Le permiten establecer puntos de interrupci\u00f3n, inspeccionar variables, pasar por el c\u00f3digo y ver expresiones sin escribir comandos.<\/p>\n<p>Los depuradores IDE son \u00fatiles para el desarrollo local. Para cl\u00fasteres remotos o servidores sin cabeza, <code>pdb<\/code>, <code>ipdb<\/code> y el registro suelen ser m\u00e1s pr\u00e1cticos.<\/p>\n<h3>Cu\u00e1ndo usar qu\u00e9 herramienta<\/h3>\n<table class=\"custom-table\">\n<tbody>\n<tr>\n<th>Gui\u00f3n<\/th>\n<th>herramienta recomendada<\/th>\n<\/tr>\n<tr>\n<td>gui\u00f3n r\u00e1pido o desarrollo local temprano<\/td>\n<td><code>print()<\/code> M\u00e1s afirmaciones<\/td>\n<\/tr>\n<tr>\n<td>Trazamiento de error en ipython<\/td>\n<td><code>%debug<\/code><\/td>\n<\/tr>\n<tr>\n<td>Cl\u00faster remoto sin acceso IDE<\/td>\n<td><code>python -m pdb script.py<\/code><\/td>\n<\/tr>\n<tr>\n<td>Depuraci\u00f3n interactiva con mejor contexto<\/td>\n<td><code>ipdb<\/code> o depurador IDE<\/td>\n<\/tr>\n<tr>\n<td>Diagn\u00f3sticos estilo producci\u00f3n<\/td>\n<td><code>logging<\/code> con puntos de interrupci\u00f3n estrat\u00e9gicas<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>Nivel 4: Perfiles para encontrar errores ocultos<\/h2>\n<p>El perfilado generalmente se ve como una herramienta de rendimiento, pero tambi\u00e9n ayuda a la depuraci\u00f3n. El c\u00f3digo lento suele ser un c\u00f3digo incorrecto. Los perfiladores pueden revelar bucles de Python accidental, asignaciones repetidas, c\u00e1lculos redundantes o llamadas a funciones inesperadas.<\/p>\n<h3>Cprofile: encontrar las funciones calientes<\/h3>\n<pre><code class=\"language-python\">import cProfile\nimport pstats\n\nprofiler = cProfile.Profile()\n\nprofiler.enable()\nsolve_phase_field(phi, dt, n_iterations)\nprofiler.disable()\n\nstats = pstats.Stats(profiler)\nstats.sort_stats(\"cumulative\")\nstats.print_stats(20)\n<\/code><\/pre>\n<p>Esto muestra qu\u00e9 funciones consumen m\u00e1s tiempo total. Si una funci\u00f3n auxiliar domina inesperadamente el tiempo de ejecuci\u00f3n, puede contener un error oculto o una l\u00f3gica de matriz ineficiente.<\/p>\n<h3>line_profiler: encuentra las l\u00edneas calientes<\/h3>\n<p>Cuando <code>cProfile<\/code> identifica una funci\u00f3n lenta, <code>line_profiler<\/code> puede mostrar qu\u00e9 l\u00edneas dentro de la funci\u00f3n consumen tiempo.<\/p>\n<pre><code class=\"language-bash\">pip install line_profiler\nkernprof -l -v simulation.py\n<\/code><\/pre>\n<p>Esto es \u00fatil cuando una sola l\u00ednea dentro de un bucle crea matrices repetidamente o realiza una operaci\u00f3n lenta por error.<\/p>\n<h3>Perfiles de memoria: encontrar asignaciones ocultas<\/h3>\n<p>El c\u00f3digo cient\u00edfico a menudo oculta errores de memoria, como copias accidentales o la creaci\u00f3n excesiva de matrices dentro de bucles. <code>memory_profiler<\/code> puede ayudar a realizar un seguimiento de las asignaciones.<\/p>\n<pre><code class=\"language-python\">from memory_profiler import profile\n\n@profile\ndef solve_phase_field(phi, dt):\n    phi_new = apply_diffusion(phi, dt)\n    return phi_new\n<\/code><\/pre>\n<p>Los perfiles de memoria l\u00ednea por l\u00ednea pueden revelar d\u00f3nde se crean y descartan grandes matrices.<\/p>\n<h3>Perfilar como depuraci\u00f3n<\/h3>\n<p>El perfilado ayuda cuando un solucionador es a la vez incorrecto y lento. Por ejemplo, un corte equivocado puede calcular la energ\u00eda sobre la regi\u00f3n equivocada. Un perfil puede mostrar que el c\u00e1lculo de la energ\u00eda es inesperadamente caro, lo que le indica la operaci\u00f3n de la matriz.<\/p>\n<p>Las afirmaciones confirman el error. El perfilado le ayuda a encontrar d\u00f3nde buscar.<\/p>\n<h2>Nivel 5: Pruebas y prevenci\u00f3n de regresi\u00f3n<\/h2>\n<p>El nivel final de depuraci\u00f3n es la prevenci\u00f3n. Despu\u00e9s de corregir un error, escriba una prueba que reproduzca la falla y demuestre que la soluci\u00f3n funciona.<\/p>\n<h3>El patr\u00f3n de pruebas cient\u00edficas<\/h3>\n<pre><code class=\"language-python\">import pytest\nimport numpy as np\n\n@pytest.mark.parametrize(\"mesh_size\", [10, 20, 50])\ndef test_energy_decreases(mesh_size):\n    \"\"\"Energy should decrease during simple diffusion.\"\"\"\n    phi = init_phi(mesh_size)\n    energy_history = []\n    \n    for step in range(100):\n        energy_history.append(compute_energy(phi))\n        phi = solve_step(phi, dt=0.01)\n    \n    energy_changes = np.diff(energy_history)\n    assert np.all(energy_changes &lt;= 1e-10)\n<\/code><\/pre>\n<p>Esta prueba verifica el comportamiento f\u00edsico, no solo la sintaxis. Una simulaci\u00f3n correcta no debe ejecutarse simplemente. Debe conservar las cantidades esperadas, respetar los l\u00edmites y converger con el refinamiento.<\/p>\n<h3>La pir\u00e1mide de prueba del c\u00f3digo cient\u00edfico<\/h3>\n<ul>\n<li>Las pruebas unitarias son r\u00e1pidas y verifican funciones individuales como <code>compute_gradient()<\/code> o <code>apply_boundary_conditions()<\/code>.<\/li>\n<li>Las pruebas de integraci\u00f3n ejecutan comprobaciones a nivel de solucionador contra soluciones anal\u00edticas o fabricadas.<\/li>\n<li>Las pruebas de regresi\u00f3n comparan las simulaciones completas con los resultados de l\u00ednea de base de confianza.<\/li>\n<\/ul>\n<p>El principio clave es simple: probar la f\u00edsica, no solo la ruta del c\u00f3digo.<\/p>\n<h2>Trampas de depuraci\u00f3n cient\u00edfica comunes<\/h2>\n<h3>Nan e infinito<\/h3>\n<p>Los valores de NaN e Infinity son comunes en el c\u00f3digo cient\u00edfico. A menudo aparecen despu\u00e9s de la divisi\u00f3n por valores cercanos a cero, <code>log(0)<\/code>, <code>sqrt<\/code> de valores negativos o desbordamiento en exponenciales.<\/p>\n<pre><code class=\"language-python\">phi = np.zeros((100, 100))\nphi[50, 50] = 1.0\n\nresult = phi \/ (phi + 1e-300)\n<\/code><\/pre>\n<p>Compruebe los valores finitos despu\u00e9s de las operaciones num\u00e9ricas:<\/p>\n<pre><code class=\"language-python\">assert np.isfinite(result).all(), (\n    f\"NaN or Inf detected: min={np.nanmin(result)}, max={np.nanmax(result)}\"\n)\n<\/code><\/pre>\n<h3>Discrepancias de forma de matriz<\/h3>\n<p>Los errores de forma de matriz son comunes cuando se mueven entre matrices de solucionador aplanados y campos 2D o 3D.<\/p>\n<pre><code class=\"language-python\">print(f\"phi shape: {phi.shape}\")\nprint(f\"expected shape: {expected_shape}\")\n<\/code><\/pre>\n<p>Las causas comunes incluyen aplanamiento accidental, indexaci\u00f3n que elimina una dimensi\u00f3n y variables de biblioteca que almacenan datos en una forma diferente a la esperada.<\/p>\n<h3>Precisi\u00f3n de punto flotante<\/h3>\n<p>No compare las matrices de coma flotante con la igualdad exacta a menos que se espere verdaderamente la igualdad exacta. Utilice comparaciones basadas en la tolerancia.<\/p>\n<pre><code class=\"language-python\">np.testing.assert_allclose(phi, phi_new, rtol=1e-6, atol=1e-12)\n<\/code><\/pre>\n<p>Esto es especialmente importante para los solucionadores iterativos, la precisi\u00f3n mixta y las integraciones a largo plazo.<\/p>\n<h3>Errores de la condici\u00f3n de l\u00edmite<\/h3>\n<p>Los errores de las condiciones de contorno son comunes porque el c\u00f3digo a menudo se ejecuta incluso cuando las celdas o las caras incorrectas est\u00e1n restringidas.<\/p>\n<pre><code class=\"language-python\"># Wrong: overwrites all cells\nphi[:] = boundary_value\n\n# Better: apply only to selected boundary locations\nphi[boundary_mask] = boundary_value\n<\/code><\/pre>\n<p>Siempre verifique que los valores de l\u00edmite se apliquen solo donde se pretenda y que los valores interiores no se sobrescriban.<\/p>\n<h3>Convergencia y estabilidad<\/h3>\n<p>Las simulaciones pueden divergir silenciosamente cuando los pasos de tiempo son demasiado grandes o las tolerancias del solucionador son demasiado bajas. monitorear las cantidades conservadas o acotadas a lo largo del tiempo.<\/p>\n<pre><code class=\"language-python\">if energy &gt; prev_energy * 1.1:\n    print(f\"Energy growing. Reducing dt from {dt} to {dt \/ 2}\")\n    dt \/= 2\n<\/code><\/pre>\n<p>Realice un seguimiento de la energ\u00eda, la masa, el impulso, los l\u00edmites, los residuos y el comportamiento de paso de tiempo. Trazarlos durante la depuraci\u00f3n.<\/p>\n<h2>La escalera de escalada de depuraci\u00f3n<\/h2>\n<p>Utilice el nivel de depuraci\u00f3n m\u00e1s bajo que proporcione suficiente informaci\u00f3n.<\/p>\n<pre><code>Level 1: print()      \u2014 quick inspection\nLevel 2: assert()     \u2014 sanity checks and invariants\nLevel 3: pdb\/ipdb     \u2014 interactive state inspection\nLevel 4: profiling    \u2014 performance bugs and hidden inefficiency\nLevel 5: pytest       \u2014 regression prevention\n<\/code><\/pre>\n<p>Escalar cuando sea necesario:<\/p>\n<ul>\n<li>Si <code>print()<\/code> da suficiente contexto, permanezca en el nivel 1.<\/li>\n<li>Si necesita verificar invariantes, use aserciones.<\/li>\n<li>Si necesita inspeccionar el estado en una l\u00ednea espec\u00edfica, use <code>pdb<\/code> o <code>ipdb<\/code>.<\/li>\n<li>Si el c\u00f3digo es incorrecto y lento, perfilalo.<\/li>\n<li>Si desea evitar que el error regrese, escriba una prueba.<\/li>\n<\/ul>\n<h2>Un ejemplo pr\u00e1ctico de depuraci\u00f3n: arreglar una simulaci\u00f3n Fipy<\/h2>\n<p>Supongamos que una simulaci\u00f3n de difusi\u00f3n f\u00edsimo produce valores de concentraci\u00f3n ilimitados en lugar de difusi\u00f3n suave. Comience por escribir una versi\u00f3n m\u00ednima y clara del problema.<\/p>\n<pre><code class=\"language-python\">import numpy as np\nfrom fipy import Grid2D, CellVariable, TransientTerm, DiffusionTerm\n\nmesh = Grid2D(nx=50, ny=50, dx=1.0, dy=1.0)\n\nphi = CellVariable(name=\"concentration\", mesh=mesh, value=0.0)\nx, y = mesh.cellCenters\n\n# Initial hot spot in the center\nphi.setValue(\n    1.0,\n    where=((x - 25.0)**2 + (y - 25.0)**2) &lt; 25.0\n)\n\neq = TransientTerm(var=phi) == DiffusionTerm(coeff=1.0, var=phi)\n\ndt = 0.01\n\nprint(f\"Initial: min={phi.value.min()}, max={phi.value.max()}\")\n\nfor step in range(100):\n    eq.solve(var=phi, dt=dt)\n    \n    assert np.isfinite(phi.value).all(), \"NaN or Inf detected\"\n    assert phi.value.min() &gt;= -1e-10, f\"Negative value at step {step}\"\n    \nprint(f\"Final: min={phi.value.min()}, max={phi.value.max()}\")\n<\/code><\/pre>\n<p>luego depurar sistem\u00e1ticamente.<\/p>\n<h3>Paso 1: Haz que falle<\/h3>\n<p>Log M\u00ednimo, M\u00e1ximo, Masa y Energ\u00eda antes y despu\u00e9s de la carrera.<\/p>\n<pre><code class=\"language-python\">print(f\"min={phi.value.min()}, max={phi.value.max()}\")\nprint(f\"mass={np.sum(phi.value * mesh.cellVolumes)}\")\nprint(f\"energy={np.sum(phi.value**2 * mesh.cellVolumes)}\")\n<\/code><\/pre>\n<h3>Paso 2: Dividir y conquistar<\/h3>\n<p>Pruebe solo el t\u00e9rmino de difusi\u00f3n. Elimine los t\u00e9rminos de reacci\u00f3n, los t\u00e9rminos de advecci\u00f3n, las fuentes no lineales y las condiciones de contorno complejas hasta que la falla desaparezca o se a\u00edsle.<\/p>\n<h3>Paso 3: Cambiar una cosa<\/h3>\n<p>Pruebe un paso de tiempo m\u00e1s peque\u00f1o, luego compare los resultados.<\/p>\n<pre><code class=\"language-python\">dt = 0.001\n<\/code><\/pre>\n<p>Si el error persiste con un paso de tiempo m\u00e1s peque\u00f1o, el problema puede ser espacial, estructural o relacionado con las condiciones de los l\u00edmites en lugar de la estabilidad del tiempo.<\/p>\n<h3>Paso 4: Usa el depurador<\/h3>\n<p>Ca\u00edda en un depurador cerca del paso defectuoso e inspeccione los valores, la forma de la malla, las m\u00e1scaras y las condiciones de los l\u00edmites.<\/p>\n<pre><code class=\"language-python\">import pdb\npdb.set_trace()\n<\/code><\/pre>\n<h3>Paso 5: agregar una prueba<\/h3>\n<p>Despu\u00e9s de corregir el error, agregue una prueba de regresi\u00f3n.<\/p>\n<pre><code class=\"language-python\">def test_diffusion_mass_stays_finite():\n    phi_initial, phi_final, volumes = run_small_diffusion_case()\n    \n    mass_initial = np.sum(phi_initial * volumes)\n    mass_final = np.sum(phi_final * volumes)\n    \n    np.testing.assert_allclose(mass_initial, mass_final, rtol=1e-6)\n    assert np.isfinite(phi_final).all()\n<\/code><\/pre>\n<h2>Resumen y pr\u00f3ximos pasos<\/h2>\n<p>Depurar el c\u00f3digo cient\u00edfico Python es una habilidad progresiva. Comience con declaraciones impresas, pase a las aserciones, use depuradores cuando se necesite una inspecci\u00f3n de estado, perfile cuando el c\u00f3digo sea lento o sospechoso, y escriba pruebas para evitar regresiones.<\/p>\n<p>El principio m\u00e1s importante es aislar el error antes de arreglarlo. Un error que puede reproducir en un peque\u00f1o caso de prueba es mucho m\u00e1s f\u00e1cil de resolver. Un error que solo aparece dentro de una gran simulaci\u00f3n sigue siendo un misterio.<\/p>\n<p>Para el c\u00f3digo cient\u00edfico, recuerde estas reglas:<\/p>\n<ul>\n<li>Compruebe si hay NAN e infinito despu\u00e9s de operaciones num\u00e9ricas.<\/li>\n<li>Imprimir formas de matriz cuando la indexaci\u00f3n se vuelve compleja.<\/li>\n<li>Supervise las cantidades conservadas como la masa, la energ\u00eda y el momento.<\/li>\n<li>Pruebe las condiciones de los l\u00edmites por separado de la l\u00f3gica interior.<\/li>\n<li>Use afirmaciones como primera l\u00ednea de defensa contra fallas num\u00e9ricas silenciosas.<\/li>\n<\/ul>\n<h3>Pr\u00f3ximos pasos<\/h3>\n<ul>\n<li>Comience a usar la escalera de escalada de depuraci\u00f3n: Comience con <code>print()<\/code> y escale solo cuando sea necesario.<\/li>\n<li>Agrega aserciones antes y despu\u00e9s de las funciones del solucionador.<\/li>\n<li>Configure el registro para los diagn\u00f3sticos de simulaci\u00f3n.<\/li>\n<li>Escriba al menos un caso de prueba que reproduzca un error com\u00fan.<\/li>\n<\/ul>\n<p>La depuraci\u00f3n no es un signo de debilidad. Es parte de escribir c\u00f3digo que importa. Las habilidades que desarrolle al depurar el c\u00f3digo cient\u00edfico Python ayudar\u00e1n en todo tipo de proyectos de software num\u00e9rico y de investigaci\u00f3n.<\/p>\n<h2>Gu\u00edas relacionadas<\/h2>\n<ul>\n<li><a href=\"https:\/\/matforge.org\/performance-profiling-optimization-python-pde-solvers\/\">performance perfilando y optimizaci\u00f3n para los solucionadores de PDE de Python: una gu\u00eda pr\u00e1ctica<\/a> \u2014 herramientas de perfilado, NUMBA y optimizaci\u00f3n de memoria.<\/li>\n<li><a href=\"https:\/\/matforge.org\/unit-testing-scientific-code-pytest-strategies-research-projects\/\">pruebas unitarias para c\u00f3digo cient\u00edfico: estrategias pytest<\/a> \u2014 precisi\u00f3n num\u00e9rica y patrones de prueba.<\/li>\n<li><a href=\"https:\/\/matforge.org\/continuous-integration-research-software-automated-testing-validation\/\">Integraci\u00f3n continua para software de investigaci\u00f3n: pruebas y validaci\u00f3n automatizadas<\/a> \u2014 CI canalizaciones y pruebas automatizadas.<\/li>\n<li><a href=\"https:\/\/matforge.org\/best-practices-for-maintaining-scientific-code\/\">Mejores pr\u00e1cticas para mantener el c\u00f3digo cient\u00edfico<\/a> \u2014 estructura del proyecto, control de versiones y documentaci\u00f3n.<\/li>\n<li><a href=\"https:\/\/matforge.org\/using-fipy-for-phase-field-modeling\/\">usando fipy para el modelado de campo de fase<\/a> \u2014 patrones de implementaci\u00f3n fipy.<\/li>\n<\/ul>\n<h2>\u00bfNecesita ayuda para depurar su c\u00f3digo de simulaci\u00f3n?<\/h2>\n<p>Depuraci\u00f3n de simulaciones cient\u00edficas complejas puede llevar mucho tiempo, especialmente cuando no est\u00e1 seguro de si el error est\u00e1 en la configuraci\u00f3n de c\u00f3digo, malla, condiciones de contorno o del solucionador.<\/p>\n<p>Nuestro equipo puede ayudar con los flujos de trabajo de depuraci\u00f3n sistem\u00e1ticos, los casos de pruebas num\u00e9ricas, las verificaciones de cordura para las leyes de conservaci\u00f3n y las canalizaciones de CI con pruebas de regresi\u00f3n.<\/p>\n","protected":false,"raw":"<h2>Comida clave<\/h2>\n<ul>\n<li>Depuraci\u00f3n El c\u00f3digo cient\u00edfico de Python sigue una escala de escalamiento: <code>print<\/code>, <code>assert<\/code>, <code>pdb<\/code>, perfiles y pruebas.<\/li>\n<li>La mayor\u00eda de los errores cient\u00edficos son num\u00e9ricos, como los valores de NAN, las discrepancias en la forma de los arreglos, la p\u00e9rdida de precisi\u00f3n o los pasos de tiempo inestables.<\/li>\n<li><code>print()<\/code> Atrapa muchos errores para principiantes, pero las afirmaciones y los depuradores facilitan el aislamiento de las fallas.<\/li>\n<li>Un flujo de trabajo de depuraci\u00f3n cient\u00edfica confiable es: hacer que falle, a\u00edsle el problema, cambie una cosa, verifique y agregue una prueba.<\/li>\n<li>La creaci\u00f3n de perfiles puede revelar errores ocultos porque el c\u00f3digo lento es a menudo un signo de l\u00f3gica de matriz incorrecta, bucles accidentales o una asignaci\u00f3n excesiva.<\/li>\n<\/ul>\n<p>Depurar el c\u00f3digo cient\u00edfico Python es una de las habilidades m\u00e1s frustrantes que se pueden desarrollar. Escribe lo que deber\u00eda ser una simple simulaci\u00f3n de difusi\u00f3n de calor, el c\u00f3digo se ejecuta sin errores y la salida es completamente incorrecta.<\/p>\n<p>Sin choque. Sin rastreo. solo n\u00fameros incorrectos en silencio.<\/p>\n<p>Ese es el desaf\u00edo \u00fanico de la depuraci\u00f3n cient\u00edfica. Los insectos m\u00e1s peligrosos son a menudo los que no se estrellan en absoluto. Un n\u00famero incorrecto puede propagarse a trav\u00e9s de miles de iteraciones y producir un resultado que parece f\u00edsicamente plausible hasta que verifique la conservaci\u00f3n, la estabilidad o la convergencia.<\/p>\n<p>Esta gu\u00eda explica c\u00f3mo depurar el c\u00f3digo cient\u00edfico de Python en varios niveles: declaraciones de impresi\u00f3n, registro, aserciones, depuraci\u00f3n interactiva, perfiles y pruebas de regresi\u00f3n.<\/p>\n<p>Ya sea que est\u00e9 ejecutando una primera simulaci\u00f3n FIPY o depurando una canalizaci\u00f3n de investigaci\u00f3n de producci\u00f3n, este flujo de trabajo le brinda una estructura pr\u00e1ctica a seguir.<\/p>\n<h2>\u00bfQu\u00e9 tiene de diferente la depuraci\u00f3n del c\u00f3digo cient\u00edfico?<\/h2>\n<p>La depuraci\u00f3n cient\u00edfica es diferente de la depuraci\u00f3n de una aplicaci\u00f3n web, API o canalizaci\u00f3n de datos ordinaria.<\/p>\n<p>Los n\u00fameros pueden mentir. Una aplicaci\u00f3n web a menudo falla visiblemente: un bot\u00f3n no funciona, una API devuelve un error o falla una consulta de base de datos. El c\u00f3digo cient\u00edfico puede funcionar perfectamente y a\u00fan as\u00ed producir resultados incorrectos. Una concentraci\u00f3n negativa, un campo de energ\u00eda explosiva o una NAN oculta solo puede aparecer si lo comprueba directamente.<\/p>\n<p>La correcci\u00f3n se define por la f\u00edsica, no solo por la sintaxis. Un programa de Python que se ejecuta es sint\u00e1cticamente v\u00e1lido. Un programa cient\u00edfico solo es cre\u00edble si coincide con las soluciones conocidas, conserva las cantidades esperadas, respeta las condiciones de los l\u00edmites y converge bajo el refinamiento.<\/p>\n<p>Los rastros de pila a menudo apuntan a n\u00fameros internos numpy, scipy o fip. El error real puede estar en su configuraci\u00f3n, pero el mensaje de error puede aparecer en lo m\u00e1s profundo de una biblioteca. Es por eso que la depuraci\u00f3n cient\u00edfica necesita un proceso estructurado, no solo la lectura de rastreo.<\/p>\n<h2>El flujo de trabajo de depuraci\u00f3n: un modelo mental de cinco pasos<\/h2>\n<p>Un \u00fatil flujo de trabajo de depuraci\u00f3n para c\u00f3digo cient\u00edfico sigue cinco pasos.<\/p>\n<h3>Paso 1: Haz que falle<\/h3>\n<p>Su primer trabajo es crear un caso de prueba que falla cada vez. En el c\u00f3digo cient\u00edfico, esto generalmente significa construir un ejemplo reproducible m\u00ednimo que produce un resultado incorrecto.<\/p>\n<p>No necesita la simulaci\u00f3n completa. Necesita el c\u00f3digo m\u00e1s peque\u00f1o que demuestre el error.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\n# Full simulation may be hundreds of lines.\n# Start with the smallest failing update step.\n\nphi = np.ones((10, 10))\nphi[:] = 0.5\n\ngradient = np.gradient(phi)[0]\nphi_new = phi - 0.1 * gradient\n\nprint(f\"min(phi_new) = {np.min(phi_new)}\")\nprint(f\"max(phi_new) = {np.max(phi_new)}\")\n<\/code><\/pre>\n<p>Al aislar el paso de actualizaci\u00f3n, crea un caso reproducible. Esta es la base de cada paso de depuraci\u00f3n posterior.<\/p>\n<h3>Paso 2: Dividir y conquistar<\/h3>\n<p>Una vez que tengas un caso fallido, a\u00edslalo m\u00e1s. Encuentre el m\u00f3dulo, funci\u00f3n, l\u00ednea o t\u00e9rmino de f\u00edsica responsable de la falla.<\/p>\n<p>Para el c\u00f3digo de simulaci\u00f3n, una t\u00e1ctica \u00fatil es probar cada t\u00e9rmino de f\u00edsica por separado. Si su modelo combina difusi\u00f3n, reacci\u00f3n y advecci\u00f3n, pruebe cada uno solo antes de depurar el sistema acoplado.<\/p>\n<pre><code class=\"language-python\">solution_diffusion = solve_diffusion_only(initial_conditions, dt)\nassert np.all(solution_diffusion &gt;= 0), \"Diffusion produced negative values\"\n\nsolution_reaction = solve_reaction_only(initial_conditions, dt)\nassert np.all(solution_reaction &gt;= 0), \"Reaction produced negative values\"\n\nsolution_coupled = solve_coupled(initial_conditions, dt)\n<\/code><\/pre>\n<p>Esto reduce el espacio de b\u00fasqueda. En lugar de depurar toda la simulaci\u00f3n, depura un t\u00e9rmino o un mecanismo de acoplamiento.<\/p>\n<h3>Paso 3: Cambiar una cosa a la vez<\/h3>\n<p>La depuraci\u00f3n cient\u00edfica se vuelve confusa cuando cambias varias variables a la vez. Si cambia el paso de tiempo, las condiciones de los l\u00edmites, la tolerancia al solucionador y la condici\u00f3n inicial juntos, no puede saber qu\u00e9 cambio importaba.<\/p>\n<p>Cambiar un par\u00e1metro. correr comparar documento.<\/p>\n<p>Utilice el control de versiones para realizar un seguimiento de los cambios. Incluso las confirmaciones simples como \"DT cambiadas de 0.01 a 0.001\" pueden ahorrar horas despu\u00e9s.<\/p>\n<h3>Paso 4: Usa el depurador<\/h3>\n<p>Cuando las impresiones y las aserciones no sean suficientes, use <code>pdb<\/code>, <code>ipdb<\/code> o un depurador IDE. Un depurador le permite pausar la ejecuci\u00f3n, inspeccionar variables, pasar a trav\u00e9s del c\u00f3digo y verificar por qu\u00e9 cambi\u00f3 un valor.<\/p>\n<h3>Paso 5: agregar a la suite de prueba<\/h3>\n<p>Despu\u00e9s de corregir un error, agregue una prueba que lo habr\u00eda detectado. Esto evita que el mismo error regrese m\u00e1s tarde.<\/p>\n<pre><code class=\"language-python\">def test_no_negative_phases():\n    \"\"\"Verify phase field stays non-negative after diffusion.\"\"\"\n    phi = np.ones((10, 10))\n    phi = diffusion_step(phi, dt=0.01)\n    assert np.min(phi) &gt;= 0, f\"Got min value {np.min(phi)}\"\n<\/code><\/pre>\n<p>El flujo de trabajo es simple: aislar, dividir, cambiar una cosa, depurar y probar. El resto de esta gu\u00eda explica qu\u00e9 herramientas usar en cada nivel.<\/p>\n<h2>Nivel 1: Imprimir declaraciones y registro<\/h2>\n<p><code>print()<\/code> sigue siendo \u00fatil. Es la herramienta de depuraci\u00f3n m\u00e1s simple y atrapa muchos errores tempranos. La clave es usarlo con estructura.<\/p>\n<h3>El problema con las malas impresiones<\/h3>\n<p>Un error principiante com\u00fan es imprimir valores sin contexto.<\/p>\n<pre><code class=\"language-python\">for i in range(100):\n    print(phi[i])\n<\/code><\/pre>\n<p>Despu\u00e9s de algunas iteraciones, tiene muchos n\u00fameros sin un significado claro. No sabe qu\u00e9 variable, paso de tiempo o condici\u00f3n produjo cada l\u00ednea.<\/p>\n<h3>La forma correcta: impresiones estructuradas<\/h3>\n<p>Etiqueta todo. Incluya el paso de tiempo, el nombre de la variable, el m\u00ednimo, el m\u00e1ximo y cualquier cantidad conservada que le interese.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\nprint(\n    f\"[t={t:06.4f}] \"\n    f\"min(phi)={np.min(phi):.6f}, \"\n    f\"max(phi)={np.max(phi):.6f}\"\n)\n\nprint(\n    f\"[t={t:06.4f}] \"\n    f\"energy={np.sum(phi * phi):.6f}, \"\n    f\"mass={np.sum(phi):.6f}\"\n)\n<\/code><\/pre>\n<p>Esta salida es f\u00e1cil de escanear:<\/p>\n<pre><code>[t=0.0010] min(phi)=0.000000, max(phi)=1.000000\n[t=0.0010] energy=0.850000, mass=1.000000\n[t=0.0020] min(phi)=0.000000, max(phi)=1.023456\n[t=0.0020] energy=0.873456, mass=1.012345\n<\/code><\/pre>\n<p>Puede ver inmediatamente que el valor m\u00e1ximo se elev\u00f3 por encima de 1.0 y la masa cambi\u00f3. Esas son pistas \u00fatiles.<\/p>\n<h3>Registrar vs declaraciones de impresi\u00f3n<\/h3>\n<p>Para una depuraci\u00f3n seria, use el m\u00f3dulo <code>logging<\/code> de Python en lugar de RAW <code>print()<\/code>.<\/p>\n<pre><code class=\"language-python\">import logging\n\nlogging.basicConfig(\n    level=logging.DEBUG,\n    format=\"%(levelname)s: %(message)s\"\n)\n\nlogger = logging.getLogger(__name__)\n\nlogger.debug(\"Running diffusion step at t=%f, dt=%f\", t, dt)\nlogger.warning(\"Energy increased by %.5f\", energy_change)\n<\/code><\/pre>\n<p>El registro tiene varias ventajas:<\/p>\n<ul>\n<li>niveles como <code>DEBUG<\/code>, <code>WARNING<\/code> y <code>ERROR<\/code>.<\/li>\n<li>Marcas de tiempo opcionales y salida de archivo.<\/li>\n<li>F\u00e1cil activaci\u00f3n o desactivaci\u00f3n sin eliminar el c\u00f3digo de depuraci\u00f3n.<\/li>\n<li>Diagn\u00f3sticos m\u00e1s limpios durante largos recorridos de simulaci\u00f3n.<\/li>\n<\/ul>\n<p>Una regla pr\u00e1ctica es usar <code>print()<\/code> para scripts exploratorios r\u00e1pidos y <code>logging<\/code> para c\u00f3digo de simulaci\u00f3n reutilizable o de producci\u00f3n.<\/p>\n<h2>Nivel 2: Aserciones y controles de cordura<\/h2>\n<p>Las afirmaciones son como declaraciones impresas que se niegan a permanecer en silencio. Producen un error cuando se viola una suposici\u00f3n.<\/p>\n<h3>El patr\u00f3n: suposiciones primero<\/h3>\n<p>El patr\u00f3n m\u00e1s \u00fatil es verificar las entradas, ejecutar el solucionador y verificar las salidas.<\/p>\n<pre><code class=\"language-python\">import numpy as np\n\ndef solve_diffusion(phi, dt, diffusion_coeff):\n    # Preconditions\n    assert np.all(phi &gt;= 0), f\"Negative phase: {np.min(phi)}\"\n    assert np.all(phi &lt;= 1), f\"Phase &gt; 1: {np.max(phi)}\"\n    assert np.isfinite(phi).all(), \"Non-finite input values detected\"\n    \n    # Solver step\n    phi_new = apply_diffusion(phi, dt, diffusion_coeff)\n    \n    # Postconditions\n    assert np.isfinite(phi_new).all(), \"Solver produced NaN or Inf\"\n    assert np.all(phi_new &gt;= 0), f\"Negative output: {np.min(phi_new)}\"\n    \n    return phi_new\n<\/code><\/pre>\n<p>Esto convierte la falla num\u00e9rica silenciosa en un error claro con la ubicaci\u00f3n y el contexto.<\/p>\n<h3>La filosof\u00eda de la afirmaci\u00f3n<\/h3>\n<p>Las afirmaciones no se tratan solo de atrapar errores. Fijan errores.<\/p>\n<p>Una afirmaci\u00f3n que falla cerca del comienzo de un solucionador le dice d\u00f3nde se rompi\u00f3 la suposici\u00f3n. Una nana que aparece cientos de l\u00edneas m\u00e1s tarde te dice mucho menos.<\/p>\n<p>Los lugares \u00fatiles para las afirmaciones incluyen:<\/p>\n<ul>\n<li>Llamadas antes y despu\u00e9s del solucionador.<\/li>\n<li>en los l\u00edmites del m\u00f3dulo donde se intercambian los datos.<\/li>\n<li>Despu\u00e9s de operaciones de malla como refinamiento, reajuste o engrosamiento.<\/li>\n<li>despu\u00e9s de aplicar las condiciones de contorno.<\/li>\n<\/ul>\n<h3>Una advertencia sobre las afirmaciones<\/h3>\n<p>No use las afirmaciones en exceso en bucles internos caros a menos que las necesite. Pueden agregar sobrecarga de tiempo de ejecuci\u00f3n y hacer que la depuraci\u00f3n sea ruidosa.<\/p>\n<p>Use aserciones para invariantes y condiciones previas: condiciones que nunca deben violarse si el c\u00f3digo es correcto.<\/p>\n<h2>Nivel 3: El depurador de Python<\/h2>\n<p>Cuando las declaraciones de impresi\u00f3n no sean suficientes, use un depurador interactivo. Un depurador le permite pausar el programa, inspeccionar el estado y pasar por la l\u00f3gica.<\/p>\n<h3>La herramienta cl\u00e1sica: PDB<\/h3>\n<p><code>pdb<\/code> es el depurador incorporado de Python. Est\u00e1 disponible en cada instalaci\u00f3n de Python.<\/p>\n<p>En ipython, puede usar la depuraci\u00f3n post-mortem despu\u00e9s de un error:<\/p>\n<pre><code class=\"language-python\">In [1]: %run simulation.py\n\nIn [2]: %debug\n<\/code><\/pre>\n<p>Esto lo deja caer en el depurador en el punto de falla.<\/p>\n<p>Para los scripts de l\u00ednea de comandos, inicie el script con el depurador:<\/p>\n<pre><code class=\"language-bash\">python -m pdb simulation.py\n<\/code><\/pre>\n<p>Los comandos \u00fatiles incluyen:<\/p>\n<ul>\n<li><code>c<\/code>: Contin\u00fae la ejecuci\u00f3n.<\/li>\n<li><code>n<\/code>: Mover a la siguiente l\u00ednea.<\/li>\n<li><code>s<\/code>: Paso a una llamada de funci\u00f3n.<\/li>\n<li><code>b<\/code>: Establezca un punto de interrupci\u00f3n.<\/li>\n<li><code>p variable_name<\/code>: imprime una variable.<\/li>\n<li><code>q<\/code>: salga del depurador.<\/li>\n<\/ul>\n<p>Tambi\u00e9n puede insertar un punto de interrupci\u00f3n directamente en el c\u00f3digo:<\/p>\n<pre><code class=\"language-python\">def solve_phase_field(phi, dt):\n    import pdb\n    pdb.set_trace()\n    \n    phi_new = update_phase_field(phi, dt)\n    return phi_new\n<\/code><\/pre>\n<h3>Depuraci\u00f3n de IPDB e IPython<\/h3>\n<p><code>ipdb<\/code> es una versi\u00f3n mejorada de <code>pdb<\/code>. Proporciona la finalizaci\u00f3n de la pesta\u00f1a, un mejor formato y una experiencia interactiva m\u00e1s c\u00f3moda.<\/p>\n<pre><code class=\"language-bash\">pip install ipdb\n<\/code><\/pre>\n<pre><code class=\"language-python\">import ipdb\nipdb.set_trace()\n<\/code><\/pre>\n<p>Para los usuarios de IPython, <code>%debug<\/code> suele ser la opci\u00f3n m\u00e1s r\u00e1pida despu\u00e9s de una excepci\u00f3n.<\/p>\n<h3>Depuradores IDE<\/h3>\n<p>PyCharm, VS Code y Spyder incluyen depuradores gr\u00e1ficos. Le permiten establecer puntos de interrupci\u00f3n, inspeccionar variables, pasar por el c\u00f3digo y ver expresiones sin escribir comandos.<\/p>\n<p>Los depuradores IDE son \u00fatiles para el desarrollo local. Para cl\u00fasteres remotos o servidores sin cabeza, <code>pdb<\/code>, <code>ipdb<\/code> y el registro suelen ser m\u00e1s pr\u00e1cticos.<\/p>\n<h3>Cu\u00e1ndo usar qu\u00e9 herramienta<\/h3>\n<table class=\"custom-table\">\n<tbody><tr>\n<th>Gui\u00f3n<\/th>\n<th>herramienta recomendada<\/th>\n<\/tr>\n<tr>\n<td>gui\u00f3n r\u00e1pido o desarrollo local temprano<\/td>\n<td><code>print()<\/code> M\u00e1s afirmaciones<\/td>\n<\/tr>\n<tr>\n<td>Trazamiento de error en ipython<\/td>\n<td><code>%debug<\/code><\/td>\n<\/tr>\n<tr>\n<td>Cl\u00faster remoto sin acceso IDE<\/td>\n<td><code>python -m pdb script.py<\/code><\/td>\n<\/tr>\n<tr>\n<td>Depuraci\u00f3n interactiva con mejor contexto<\/td>\n<td><code>ipdb<\/code> o depurador IDE<\/td>\n<\/tr>\n<tr>\n<td>Diagn\u00f3sticos estilo producci\u00f3n<\/td>\n<td><code>logging<\/code> con puntos de interrupci\u00f3n estrat\u00e9gicas<\/td>\n<\/tr>\n<\/tbody><\/table>\n<h2>Nivel 4: Perfiles para encontrar errores ocultos<\/h2>\n<p>El perfilado generalmente se ve como una herramienta de rendimiento, pero tambi\u00e9n ayuda a la depuraci\u00f3n. El c\u00f3digo lento suele ser un c\u00f3digo incorrecto. Los perfiladores pueden revelar bucles de Python accidental, asignaciones repetidas, c\u00e1lculos redundantes o llamadas a funciones inesperadas.<\/p>\n<h3>Cprofile: encontrar las funciones calientes<\/h3>\n<pre><code class=\"language-python\">import cProfile\nimport pstats\n\nprofiler = cProfile.Profile()\n\nprofiler.enable()\nsolve_phase_field(phi, dt, n_iterations)\nprofiler.disable()\n\nstats = pstats.Stats(profiler)\nstats.sort_stats(\"cumulative\")\nstats.print_stats(20)\n<\/code><\/pre>\n<p>Esto muestra qu\u00e9 funciones consumen m\u00e1s tiempo total. Si una funci\u00f3n auxiliar domina inesperadamente el tiempo de ejecuci\u00f3n, puede contener un error oculto o una l\u00f3gica de matriz ineficiente.<\/p>\n<h3>line_profiler: encuentra las l\u00edneas calientes<\/h3>\n<p>Cuando <code>cProfile<\/code> identifica una funci\u00f3n lenta, <code>line_profiler<\/code> puede mostrar qu\u00e9 l\u00edneas dentro de la funci\u00f3n consumen tiempo.<\/p>\n<pre><code class=\"language-bash\">pip install line_profiler\nkernprof -l -v simulation.py\n<\/code><\/pre>\n<p>Esto es \u00fatil cuando una sola l\u00ednea dentro de un bucle crea matrices repetidamente o realiza una operaci\u00f3n lenta por error.<\/p>\n<h3>Perfiles de memoria: encontrar asignaciones ocultas<\/h3>\n<p>El c\u00f3digo cient\u00edfico a menudo oculta errores de memoria, como copias accidentales o la creaci\u00f3n excesiva de matrices dentro de bucles. <code>memory_profiler<\/code> puede ayudar a realizar un seguimiento de las asignaciones.<\/p>\n<pre><code class=\"language-python\">from memory_profiler import profile\n\n@profile\ndef solve_phase_field(phi, dt):\n    phi_new = apply_diffusion(phi, dt)\n    return phi_new\n<\/code><\/pre>\n<p>Los perfiles de memoria l\u00ednea por l\u00ednea pueden revelar d\u00f3nde se crean y descartan grandes matrices.<\/p>\n<h3>Perfilar como depuraci\u00f3n<\/h3>\n<p>El perfilado ayuda cuando un solucionador es a la vez incorrecto y lento. Por ejemplo, un corte equivocado puede calcular la energ\u00eda sobre la regi\u00f3n equivocada. Un perfil puede mostrar que el c\u00e1lculo de la energ\u00eda es inesperadamente caro, lo que le indica la operaci\u00f3n de la matriz.<\/p>\n<p>Las afirmaciones confirman el error. El perfilado le ayuda a encontrar d\u00f3nde buscar.<\/p>\n<h2>Nivel 5: Pruebas y prevenci\u00f3n de regresi\u00f3n<\/h2>\n<p>El nivel final de depuraci\u00f3n es la prevenci\u00f3n. Despu\u00e9s de corregir un error, escriba una prueba que reproduzca la falla y demuestre que la soluci\u00f3n funciona.<\/p>\n<h3>El patr\u00f3n de pruebas cient\u00edficas<\/h3>\n<pre><code class=\"language-python\">import pytest\nimport numpy as np\n\n@pytest.mark.parametrize(\"mesh_size\", [10, 20, 50])\ndef test_energy_decreases(mesh_size):\n    \"\"\"Energy should decrease during simple diffusion.\"\"\"\n    phi = init_phi(mesh_size)\n    energy_history = []\n    \n    for step in range(100):\n        energy_history.append(compute_energy(phi))\n        phi = solve_step(phi, dt=0.01)\n    \n    energy_changes = np.diff(energy_history)\n    assert np.all(energy_changes &lt;= 1e-10)\n<\/code><\/pre>\n<p>Esta prueba verifica el comportamiento f\u00edsico, no solo la sintaxis. Una simulaci\u00f3n correcta no debe ejecutarse simplemente. Debe conservar las cantidades esperadas, respetar los l\u00edmites y converger con el refinamiento.<\/p>\n<h3>La pir\u00e1mide de prueba del c\u00f3digo cient\u00edfico<\/h3>\n<ul>\n<li>Las pruebas unitarias son r\u00e1pidas y verifican funciones individuales como <code>compute_gradient()<\/code> o <code>apply_boundary_conditions()<\/code>.<\/li>\n<li>Las pruebas de integraci\u00f3n ejecutan comprobaciones a nivel de solucionador contra soluciones anal\u00edticas o fabricadas.<\/li>\n<li>Las pruebas de regresi\u00f3n comparan las simulaciones completas con los resultados de l\u00ednea de base de confianza.<\/li>\n<\/ul>\n<p>El principio clave es simple: probar la f\u00edsica, no solo la ruta del c\u00f3digo.<\/p>\n<h2>Trampas de depuraci\u00f3n cient\u00edfica comunes<\/h2>\n<h3>Nan e infinito<\/h3>\n<p>Los valores de NaN e Infinity son comunes en el c\u00f3digo cient\u00edfico. A menudo aparecen despu\u00e9s de la divisi\u00f3n por valores cercanos a cero, <code>log(0)<\/code>, <code>sqrt<\/code> de valores negativos o desbordamiento en exponenciales.<\/p>\n<pre><code class=\"language-python\">phi = np.zeros((100, 100))\nphi[50, 50] = 1.0\n\nresult = phi \/ (phi + 1e-300)\n<\/code><\/pre>\n<p>Compruebe los valores finitos despu\u00e9s de las operaciones num\u00e9ricas:<\/p>\n<pre><code class=\"language-python\">assert np.isfinite(result).all(), (\n    f\"NaN or Inf detected: min={np.nanmin(result)}, max={np.nanmax(result)}\"\n)\n<\/code><\/pre>\n<h3>Discrepancias de forma de matriz<\/h3>\n<p>Los errores de forma de matriz son comunes cuando se mueven entre matrices de solucionador aplanados y campos 2D o 3D.<\/p>\n<pre><code class=\"language-python\">print(f\"phi shape: {phi.shape}\")\nprint(f\"expected shape: {expected_shape}\")\n<\/code><\/pre>\n<p>Las causas comunes incluyen aplanamiento accidental, indexaci\u00f3n que elimina una dimensi\u00f3n y variables de biblioteca que almacenan datos en una forma diferente a la esperada.<\/p>\n<h3>Precisi\u00f3n de punto flotante<\/h3>\n<p>No compare las matrices de coma flotante con la igualdad exacta a menos que se espere verdaderamente la igualdad exacta. Utilice comparaciones basadas en la tolerancia.<\/p>\n<pre><code class=\"language-python\">np.testing.assert_allclose(phi, phi_new, rtol=1e-6, atol=1e-12)\n<\/code><\/pre>\n<p>Esto es especialmente importante para los solucionadores iterativos, la precisi\u00f3n mixta y las integraciones a largo plazo.<\/p>\n<h3>Errores de la condici\u00f3n de l\u00edmite<\/h3>\n<p>Los errores de las condiciones de contorno son comunes porque el c\u00f3digo a menudo se ejecuta incluso cuando las celdas o las caras incorrectas est\u00e1n restringidas.<\/p>\n<pre><code class=\"language-python\"># Wrong: overwrites all cells\nphi[:] = boundary_value\n\n# Better: apply only to selected boundary locations\nphi[boundary_mask] = boundary_value\n<\/code><\/pre>\n<p>Siempre verifique que los valores de l\u00edmite se apliquen solo donde se pretenda y que los valores interiores no se sobrescriban.<\/p>\n<h3>Convergencia y estabilidad<\/h3>\n<p>Las simulaciones pueden divergir silenciosamente cuando los pasos de tiempo son demasiado grandes o las tolerancias del solucionador son demasiado bajas. monitorear las cantidades conservadas o acotadas a lo largo del tiempo.<\/p>\n<pre><code class=\"language-python\">if energy &gt; prev_energy * 1.1:\n    print(f\"Energy growing. Reducing dt from {dt} to {dt \/ 2}\")\n    dt \/= 2\n<\/code><\/pre>\n<p>Realice un seguimiento de la energ\u00eda, la masa, el impulso, los l\u00edmites, los residuos y el comportamiento de paso de tiempo. Trazarlos durante la depuraci\u00f3n.<\/p>\n<h2>La escalera de escalada de depuraci\u00f3n<\/h2>\n<p>Utilice el nivel de depuraci\u00f3n m\u00e1s bajo que proporcione suficiente informaci\u00f3n.<\/p>\n<pre><code>Level 1: print()      \u2014 quick inspection\nLevel 2: assert()     \u2014 sanity checks and invariants\nLevel 3: pdb\/ipdb     \u2014 interactive state inspection\nLevel 4: profiling    \u2014 performance bugs and hidden inefficiency\nLevel 5: pytest       \u2014 regression prevention\n<\/code><\/pre>\n<p>Escalar cuando sea necesario:<\/p>\n<ul>\n<li>Si <code>print()<\/code> da suficiente contexto, permanezca en el nivel 1.<\/li>\n<li>Si necesita verificar invariantes, use aserciones.<\/li>\n<li>Si necesita inspeccionar el estado en una l\u00ednea espec\u00edfica, use <code>pdb<\/code> o <code>ipdb<\/code>.<\/li>\n<li>Si el c\u00f3digo es incorrecto y lento, perfilalo.<\/li>\n<li>Si desea evitar que el error regrese, escriba una prueba.<\/li>\n<\/ul>\n<h2>Un ejemplo pr\u00e1ctico de depuraci\u00f3n: arreglar una simulaci\u00f3n Fipy<\/h2>\n<p>Supongamos que una simulaci\u00f3n de difusi\u00f3n f\u00edsimo produce valores de concentraci\u00f3n ilimitados en lugar de difusi\u00f3n suave. Comience por escribir una versi\u00f3n m\u00ednima y clara del problema.<\/p>\n<pre><code class=\"language-python\">import numpy as np\nfrom fipy import Grid2D, CellVariable, TransientTerm, DiffusionTerm\n\nmesh = Grid2D(nx=50, ny=50, dx=1.0, dy=1.0)\n\nphi = CellVariable(name=\"concentration\", mesh=mesh, value=0.0)\nx, y = mesh.cellCenters\n\n# Initial hot spot in the center\nphi.setValue(\n    1.0,\n    where=((x - 25.0)**2 + (y - 25.0)**2) &lt; 25.0\n)\n\neq = TransientTerm(var=phi) == DiffusionTerm(coeff=1.0, var=phi)\n\ndt = 0.01\n\nprint(f\"Initial: min={phi.value.min()}, max={phi.value.max()}\")\n\nfor step in range(100):\n    eq.solve(var=phi, dt=dt)\n    \n    assert np.isfinite(phi.value).all(), \"NaN or Inf detected\"\n    assert phi.value.min() &gt;= -1e-10, f\"Negative value at step {step}\"\n    \nprint(f\"Final: min={phi.value.min()}, max={phi.value.max()}\")\n<\/code><\/pre>\n<p>luego depurar sistem\u00e1ticamente.<\/p>\n<h3>Paso 1: Haz que falle<\/h3>\n<p>Log M\u00ednimo, M\u00e1ximo, Masa y Energ\u00eda antes y despu\u00e9s de la carrera.<\/p>\n<pre><code class=\"language-python\">print(f\"min={phi.value.min()}, max={phi.value.max()}\")\nprint(f\"mass={np.sum(phi.value * mesh.cellVolumes)}\")\nprint(f\"energy={np.sum(phi.value**2 * mesh.cellVolumes)}\")\n<\/code><\/pre>\n<h3>Paso 2: Dividir y conquistar<\/h3>\n<p>Pruebe solo el t\u00e9rmino de difusi\u00f3n. Elimine los t\u00e9rminos de reacci\u00f3n, los t\u00e9rminos de advecci\u00f3n, las fuentes no lineales y las condiciones de contorno complejas hasta que la falla desaparezca o se a\u00edsle.<\/p>\n<h3>Paso 3: Cambiar una cosa<\/h3>\n<p>Pruebe un paso de tiempo m\u00e1s peque\u00f1o, luego compare los resultados.<\/p>\n<pre><code class=\"language-python\">dt = 0.001\n<\/code><\/pre>\n<p>Si el error persiste con un paso de tiempo m\u00e1s peque\u00f1o, el problema puede ser espacial, estructural o relacionado con las condiciones de los l\u00edmites en lugar de la estabilidad del tiempo.<\/p>\n<h3>Paso 4: Usa el depurador<\/h3>\n<p>Ca\u00edda en un depurador cerca del paso defectuoso e inspeccione los valores, la forma de la malla, las m\u00e1scaras y las condiciones de los l\u00edmites.<\/p>\n<pre><code class=\"language-python\">import pdb\npdb.set_trace()\n<\/code><\/pre>\n<h3>Paso 5: agregar una prueba<\/h3>\n<p>Despu\u00e9s de corregir el error, agregue una prueba de regresi\u00f3n.<\/p>\n<pre><code class=\"language-python\">def test_diffusion_mass_stays_finite():\n    phi_initial, phi_final, volumes = run_small_diffusion_case()\n    \n    mass_initial = np.sum(phi_initial * volumes)\n    mass_final = np.sum(phi_final * volumes)\n    \n    np.testing.assert_allclose(mass_initial, mass_final, rtol=1e-6)\n    assert np.isfinite(phi_final).all()\n<\/code><\/pre>\n<h2>Resumen y pr\u00f3ximos pasos<\/h2>\n<p>Depurar el c\u00f3digo cient\u00edfico Python es una habilidad progresiva. Comience con declaraciones impresas, pase a las aserciones, use depuradores cuando se necesite una inspecci\u00f3n de estado, perfile cuando el c\u00f3digo sea lento o sospechoso, y escriba pruebas para evitar regresiones.<\/p>\n<p>El principio m\u00e1s importante es aislar el error antes de arreglarlo. Un error que puede reproducir en un peque\u00f1o caso de prueba es mucho m\u00e1s f\u00e1cil de resolver. Un error que solo aparece dentro de una gran simulaci\u00f3n sigue siendo un misterio.<\/p>\n<p>Para el c\u00f3digo cient\u00edfico, recuerde estas reglas:<\/p>\n<ul>\n<li>Compruebe si hay NAN e infinito despu\u00e9s de operaciones num\u00e9ricas.<\/li>\n<li>Imprimir formas de matriz cuando la indexaci\u00f3n se vuelve compleja.<\/li>\n<li>Supervise las cantidades conservadas como la masa, la energ\u00eda y el momento.<\/li>\n<li>Pruebe las condiciones de los l\u00edmites por separado de la l\u00f3gica interior.<\/li>\n<li>Use afirmaciones como primera l\u00ednea de defensa contra fallas num\u00e9ricas silenciosas.<\/li>\n<\/ul>\n<h3>Pr\u00f3ximos pasos<\/h3>\n<ul>\n<li>Comience a usar la escalera de escalada de depuraci\u00f3n: Comience con <code>print()<\/code> y escale solo cuando sea necesario.<\/li>\n<li>Agrega aserciones antes y despu\u00e9s de las funciones del solucionador.<\/li>\n<li>Configure el registro para los diagn\u00f3sticos de simulaci\u00f3n.<\/li>\n<li>Escriba al menos un caso de prueba que reproduzca un error com\u00fan.<\/li>\n<\/ul>\n<p>La depuraci\u00f3n no es un signo de debilidad. Es parte de escribir c\u00f3digo que importa. Las habilidades que desarrolle al depurar el c\u00f3digo cient\u00edfico Python ayudar\u00e1n en todo tipo de proyectos de software num\u00e9rico y de investigaci\u00f3n.<\/p>\n<h2>Gu\u00edas relacionadas<\/h2>\n<ul>\n<li><a href=\"https:\/\/matforge.org\/performance-profiling-optimization-python-pde-solvers\/\">performance perfilando y optimizaci\u00f3n para los solucionadores de PDE de Python: una gu\u00eda pr\u00e1ctica<\/a> \u2014 herramientas de perfilado, NUMBA y optimizaci\u00f3n de memoria.<\/li>\n<li><a href=\"https:\/\/matforge.org\/unit-testing-scientific-code-pytest-strategies-research-projects\/\">pruebas unitarias para c\u00f3digo cient\u00edfico: estrategias pytest<\/a> \u2014 precisi\u00f3n num\u00e9rica y patrones de prueba.<\/li>\n<li><a href=\"https:\/\/matforge.org\/continuous-integration-research-software-automated-testing-validation\/\">Integraci\u00f3n continua para software de investigaci\u00f3n: pruebas y validaci\u00f3n automatizadas<\/a> \u2014 CI canalizaciones y pruebas automatizadas.<\/li>\n<li><a href=\"https:\/\/matforge.org\/best-practices-for-maintaining-scientific-code\/\">Mejores pr\u00e1cticas para mantener el c\u00f3digo cient\u00edfico<\/a> \u2014 estructura del proyecto, control de versiones y documentaci\u00f3n.<\/li>\n<li><a href=\"https:\/\/matforge.org\/using-fipy-for-phase-field-modeling\/\">usando fipy para el modelado de campo de fase<\/a> \u2014 patrones de implementaci\u00f3n fipy.<\/li>\n<\/ul>\n<h2>\u00bfNecesita ayuda para depurar su c\u00f3digo de simulaci\u00f3n?<\/h2>\n<p>Depuraci\u00f3n de simulaciones cient\u00edficas complejas puede llevar mucho tiempo, especialmente cuando no est\u00e1 seguro de si el error est\u00e1 en la configuraci\u00f3n de c\u00f3digo, malla, condiciones de contorno o del solucionador.<\/p>\n<p>Nuestro equipo puede ayudar con los flujos de trabajo de depuraci\u00f3n sistem\u00e1ticos, los casos de pruebas num\u00e9ricas, las verificaciones de cordura para las leyes de conservaci\u00f3n y las canalizaciones de CI con pruebas de regresi\u00f3n.<\/p>\n"},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 12<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span>Comida clave Depuraci\u00f3n El c\u00f3digo cient\u00edfico de Python sigue una escala de escalamiento: print, assert, pdb, perfiles y pruebas. La mayor\u00eda de los errores cient\u00edficos son num\u00e9ricos, como los valores de NAN, las discrepancias en la forma de los arreglos, la p\u00e9rdida de precisi\u00f3n o los pasos de tiempo inestables. print() Atrapa muchos errores para [&hellip;]<\/p>\n","protected":false,"raw":""},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_locale":"es_ES","_original_post":"https:\/\/matforge.org\/?p=336","iawp_total_views":0,"footnotes":""},"categories":[1],"tags":[],"class_list":["post-556","post","type-post","status-publish","format-standard","hentry","category-simulation-modeling-projects","es-ES"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python<\/title>\n<meta name=\"description\" content=\"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/\" \/>\n<meta property=\"og:locale\" content=\"es_ES\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python\" \/>\n<meta property=\"og:description\" content=\"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/\" \/>\n<meta property=\"og:site_name\" content=\"matforge.org\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-22T08:17:36+00:00\" \/>\n<meta name=\"author\" content=\"Priya Nair\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Escrito por\" \/>\n\t<meta name=\"twitter:data1\" content=\"Priya Nair\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tiempo de lectura\" \/>\n\t<meta name=\"twitter:data2\" content=\"19 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/\"},\"author\":{\"name\":\"Priya Nair\",\"@id\":\"https:\\\/\\\/matforge.org\\\/#\\\/schema\\\/person\\\/2effd7bc155a5e6357f31dac970c5795\"},\"headline\":\"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles\",\"datePublished\":\"2026-07-22T08:17:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/\"},\"wordCount\":3097,\"commentCount\":0,\"articleSection\":[\"Simulaci\u00f3n &amp; Proyectos de modelado\"],\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/\",\"url\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/\",\"name\":\"Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/matforge.org\\\/#website\"},\"datePublished\":\"2026-07-22T08:17:36+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/matforge.org\\\/#\\\/schema\\\/person\\\/2effd7bc155a5e6357f31dac970c5795\"},\"description\":\"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/#breadcrumb\"},\"inLanguage\":\"es\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/matforge.org\\\/es\\\/python-debugging-scientific-code-print-statements-profiling\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/matforge.org\\\/es\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/matforge.org\\\/#website\",\"url\":\"https:\\\/\\\/matforge.org\\\/\",\"name\":\"matforge.org\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/matforge.org\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"es\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/matforge.org\\\/#\\\/schema\\\/person\\\/2effd7bc155a5e6357f31dac970c5795\",\"name\":\"Priya Nair\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"es\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g\",\"caption\":\"Priya Nair\"},\"sameAs\":[\"http:\\\/\\\/matforge.org\"],\"url\":\"https:\\\/\\\/matforge.org\\\/author\\\/priya-nair\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python","description":"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/","og_locale":"es_ES","og_type":"article","og_title":"Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python","og_description":"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.","og_url":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/","og_site_name":"matforge.org","article_published_time":"2026-07-22T08:17:36+00:00","author":"Priya Nair","twitter_card":"summary_large_image","twitter_misc":{"Escrito por":"Priya Nair","Tiempo de lectura":"19 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/#article","isPartOf":{"@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/"},"author":{"name":"Priya Nair","@id":"https:\/\/matforge.org\/#\/schema\/person\/2effd7bc155a5e6357f31dac970c5795"},"headline":"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles","datePublished":"2026-07-22T08:17:36+00:00","mainEntityOfPage":{"@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/"},"wordCount":3097,"commentCount":0,"articleSection":["Simulaci\u00f3n &amp; Proyectos de modelado"],"inLanguage":"es","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/","url":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/","name":"Depuraci\u00f3n de c\u00f3digo cient\u00edfico Python","isPartOf":{"@id":"https:\/\/matforge.org\/#website"},"datePublished":"2026-07-22T08:17:36+00:00","author":{"@id":"https:\/\/matforge.org\/#\/schema\/person\/2effd7bc155a5e6357f31dac970c5795"},"description":"Aprenda c\u00f3mo depurar el c\u00f3digo cient\u00edfico Python con impresi\u00f3n, registro, aserciones, PDB, perfiles, pytest y controles de cordura num\u00e9ricos.","breadcrumb":{"@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/#breadcrumb"},"inLanguage":"es","potentialAction":[{"@type":"ReadAction","target":["https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/matforge.org\/es\/python-debugging-scientific-code-print-statements-profiling\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/matforge.org\/es\/"},{"@type":"ListItem","position":2,"name":"Depuraci\u00f3n de Python para c\u00f3digo cient\u00edfico: desde declaraciones impresas hasta perfiles"}]},{"@type":"WebSite","@id":"https:\/\/matforge.org\/#website","url":"https:\/\/matforge.org\/","name":"matforge.org","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/matforge.org\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"es"},{"@type":"Person","@id":"https:\/\/matforge.org\/#\/schema\/person\/2effd7bc155a5e6357f31dac970c5795","name":"Priya Nair","image":{"@type":"ImageObject","inLanguage":"es","@id":"https:\/\/secure.gravatar.com\/avatar\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f11e168d4cd2f1eff83cbb851d6cff42d81d88bb59d8831ee77468aa4a5eea88?s=96&d=mm&r=g","caption":"Priya Nair"},"sameAs":["http:\/\/matforge.org"],"url":"https:\/\/matforge.org\/author\/priya-nair\/"}]}},"_links":{"self":[{"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/posts\/556","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/comments?post=556"}],"version-history":[{"count":1,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/posts\/556\/revisions"}],"predecessor-version":[{"id":733,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/posts\/556\/revisions\/733"}],"wp:attachment":[{"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/media?parent=556"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/categories?post=556"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/matforge.org\/wp-json\/wp\/v2\/tags?post=556"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}