{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "a9bd88d2-bdc7-46be-a94c-1ecb3348a410",
   "metadata": {},
   "source": [
    "# Unsteady DDES HLPW5\n",
    "\n",
    "![HLPW5 geo](figures/HLPW5_geo.png)\n",
    "\n",
    "Accurate predictions at large angles of attack (AOA) are crucial for aircraft CFD simulations, particularly for estimating stall speed and post-stall behavior. However, since RANS models rely on a time-averaged formulation, they inherently filter out flow unsteadiness and cannot capture phenomena such as vortex shedding, transient reattachment, and fluctuating separation bubbles. As a result, RANS often predicts flow separation either too early or too late, and the size and location of the recirculation region are typically inaccurate.\n",
    "\n",
    "In this example, the HiLiftPW-5 (HLPW5) high-lift Common Research Model (CRM-HL) case is used to demonstrate the Flow360 workflow for performing an unsteady simulation using DDES to model high-AOA conditions where flow separation is expected. The volume mesh is provided directly in the Flow360 example library as the \"High Lift Prediction Workshop 5\" project, so it is loaded with `fl.Project.from_example` (shown below) and no manual mesh download or upload is required.\n",
    "\n",
    "**Note:** The settings in this example are by no means a validation setup; they are crafted to showcase the capabilities of Flow360 and we have intentionally reduced node count and example FC cost. For rigorous validation, modify the settings as needed."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8075fcbe-901c-4c69-9688-f8d668156450",
   "metadata": {},
   "source": [
    "## 1. Create Project from the Example Library\n",
    "In this example, the workflow begins with a volume mesh. The HLPW5 volume mesh is available directly in the Flow360 example library, so instead of uploading a local mesh file we copy the example project into the account with `fl.Project.from_example`. This creates a new project (with its own project ID) whose root asset is the volume mesh, which we then reference through `project.volume_mesh`. Because `from_example` copies the entire library project (including its reference case), we delete those copied cases first so the project starts clean."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "4ab30b3a-09fa-4580-b38a-ce5a03a4652d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:13.826172Z",
     "iopub.status.busy": "2026-07-14T10:17:13.826047Z",
     "iopub.status.idle": "2026-07-14T10:17:33.685960Z",
     "shell.execute_reply": "2026-07-14T10:17:33.685391Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[12:17:15] INFO: Copy operation started for project                             \n",
      "           prj-5e29b718-4757-4d17-9f46-2648c428a44b. Waiting for completion...  \n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[?25l"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[?25h"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[12:17:31] INFO: Copy operation completed successfully.                         \n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[?25l"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[?25h"
     ]
    }
   ],
   "source": [
    "import flow360 as fl\n",
    "\n",
    "project = fl.Project.from_example(by_name=\"High Lift Prediction Workshop 5\")\n",
    "\n",
    "# from_example copies the whole library project, including its reference case.\n",
    "# Delete those copied cases so the project starts clean and holds only the\n",
    "# DDES case we submit below. The volume mesh (the project root) is untouched.\n",
    "for case_id in project.get_case_ids():\n",
    "    fl.Case.from_cloud(case_id).delete()\n",
    "\n",
    "mesh_object = project.volume_mesh"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26527c70-e3a9-4062-8ed2-3f38c613ff98",
   "metadata": {},
   "source": [
    "## 2. Define time steps\n",
    "In this step we define the unsteady time-stepping settings for the DDES simulation using `fl.Unsteady`. The code below specifies the number of physical steps, the physical time-step size, the maximum number of pseudo-steps per physical step, and the CFL strategy which in this case we use adaptive CFL."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "9ba32019-2e8a-4dd7-9936-345aced242bd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.687732Z",
     "iopub.status.busy": "2026-07-14T10:17:33.687605Z",
     "iopub.status.idle": "2026-07-14T10:17:33.690791Z",
     "shell.execute_reply": "2026-07-14T10:17:33.690392Z"
    }
   },
   "outputs": [],
   "source": [
    "time_stepping = fl.Unsteady(\n",
    "    max_pseudo_steps=35,\n",
    "    steps=600,\n",
    "    step_size=0.001 * fl.u.s,\n",
    "    CFL=fl.AdaptiveCFL(),  # Optionally switch to CFL=fl.RampCFL()\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d4d5fd8-8429-4410-b72a-1ce7006d5daa",
   "metadata": {},
   "source": [
    "## 3. DDES setting \n",
    "The DDES (Delayed Detached Eddy Simulation) option enables a hybrid turbulence modeling approach suitable only for unsteady flow simulations. It is recommended for cases involving complex flow physics, such as significant separation regions or bluff body flows, as it provides higher solution fidelity than pure RANS models.\n",
    "To use DDES, define the turbulence model as below:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "169f8462-c6a3-47b5-965a-9fdc6952cd79",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.691900Z",
     "iopub.status.busy": "2026-07-14T10:17:33.691809Z",
     "iopub.status.idle": "2026-07-14T10:17:33.693859Z",
     "shell.execute_reply": "2026-07-14T10:17:33.693490Z"
    }
   },
   "outputs": [],
   "source": [
    "turbulence_model_solver = fl.SpalartAllmaras(\n",
    "    absolute_tolerance=1e-8,\n",
    "    relative_tolerance=1e-2,\n",
    "    linear_solver=fl.LinearSolver(max_iterations=25),\n",
    "    hybrid_model=fl.DetachedEddySimulation(shielding_function=\"DDES\"),\n",
    "    rotation_correction=True,\n",
    "    equation_evaluation_frequency=1,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02dfa2d8-c628-4946-bfeb-393ba345c921",
   "metadata": {},
   "source": [
    "## 4. Outputs\n",
    "A dedicated output metric has been developed for DDES simulations, available as either `SpalartAllmaras_hybridModel` or `kOmegaSST_hybridModel`, depending on the turbulence model selected by the user. This metric provides five key DDES-related variables:\n",
    "\n",
    "1) `f_d` – The shielding function that delineates the RANS and LES regions. When `f_d` = 0, the RANS model is fully applied; when `f_d` = 1, the LES model is used. Intermediate values represent a smooth transition between the two regimes.\n",
    "\n",
    "2) `r_d` – A modified ratio of the modeled length scale to the wall distance, from which `f_d` is derived.\n",
    "\n",
    "3) `DDES_lengthRANS` – The wall distance from the computational cell to the nearest solid boundary.\n",
    "\n",
    "4) `DDES_lengthScale` -  The characteristic DES length scale $$\\tilde{d} \\equiv d - f_d \\max(0, d - C_{DES}*\\Delta)$$ \n",
    "\n",
    "5) `DDES_lengthLES` – The characteristic LES length scale, $$C_{DES}*\\Delta$$\n",
    "\n",
    "Among these variables, `f_d` is the most significant, as it enables users to identify and visualize the regions dominated by RANS and DES behavior within the computational domain.\n",
    "\n",
    "![FD DDES](figures/fd_ddes.jpeg)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "30f2cea1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.694784Z",
     "iopub.status.busy": "2026-07-14T10:17:33.694683Z",
     "iopub.status.idle": "2026-07-14T10:17:33.696584Z",
     "shell.execute_reply": "2026-07-14T10:17:33.696263Z"
    }
   },
   "outputs": [],
   "source": [
    "volume_outputs = fl.VolumeOutput(\n",
    "    name=\"volume_outputs\",\n",
    "    output_fields=[\"SpalartAllmaras_hybridModel\"],\n",
    "    output_format=[\"tecplot\"],\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ef0cd6a",
   "metadata": {},
   "source": [
    "Additionally, for unsteady simulations, users may be interested in the time history of a flow field property. The following example shows a typical case where Q-criterion isosurfaces are output at a frequency of 20, with Mach number as the output field."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "5ff2dcdf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.697513Z",
     "iopub.status.busy": "2026-07-14T10:17:33.697432Z",
     "iopub.status.idle": "2026-07-14T10:17:33.699656Z",
     "shell.execute_reply": "2026-07-14T10:17:33.699304Z"
    }
   },
   "outputs": [],
   "source": [
    "iso_surface = fl.IsosurfaceOutput(\n",
    "    isosurfaces=[\n",
    "        fl.Isosurface(\n",
    "            name=\"Isosurface_Q_cri\",\n",
    "            iso_value=1e-6,\n",
    "            field=\"qcriterion\",\n",
    "        ),\n",
    "    ],\n",
    "    output_format=[\"tecplot\"],\n",
    "    output_fields=[\"Mach\"],\n",
    "    frequency=20,\n",
    "    frequency_offset=0,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5344e48a",
   "metadata": {},
   "source": [
    "## 5. Define Simulation Parameters\n",
    "For Flow360 simulations, the operating conditions, boundary conditions (which depend on the surface names of the mesh), reference geometry, and solver settings can be defined in the same way as in other examples. For brevity, user can refer to those cases for detailed descriptions. The settings for this example are provided below, including the DDES configuration to illustrate the complete model setup."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e67ed0b8-79a6-463f-8064-9da13708e089",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.700670Z",
     "iopub.status.busy": "2026-07-14T10:17:33.700584Z",
     "iopub.status.idle": "2026-07-14T10:17:33.735649Z",
     "shell.execute_reply": "2026-07-14T10:17:33.735073Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[12:17:33] INFO: using: SI unit system for unit inference.                      \n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "           WARNING: Setting ['numerical_dissipation_factor'] on                 \n",
      "           NavierStokesSolver is deprecated; set them on the RoeFlux            \n",
      "           riemann_solver instead.                                              \n"
     ]
    }
   ],
   "source": [
    "with fl.SI_unit_system:\n",
    "    params = fl.SimulationParams(\n",
    "        time_stepping=time_stepping,\n",
    "        operating_condition=fl.AerospaceCondition.from_mach(\n",
    "            mach=0.2,\n",
    "            alpha=17.05 * fl.u.deg,\n",
    "            thermal_state=fl.ThermalState(\n",
    "                temperature=289.44 * fl.u.K,\n",
    "                density=0.002063 * fl.u.kg / fl.u.m**3,\n",
    "                material=fl.Air(),\n",
    "            ),\n",
    "            reference_mach=0.2,\n",
    "        ),\n",
    "        reference_geometry=fl.ReferenceGeometry(),\n",
    "        models=[\n",
    "            fl.Wall(\n",
    "                surfaces=[\n",
    "                    mesh_object[\"fluid/FUSE\"],\n",
    "                    mesh_object[\"fluid/HORZ\"],\n",
    "                    mesh_object[\"fluid/CHINE\"],\n",
    "                    mesh_object[\"fluid/OBFLAP\"],\n",
    "                    mesh_object[\"fluid/IBSLAT\"],\n",
    "                    mesh_object[\"fluid/WING\"],\n",
    "                    mesh_object[\"fluid/VERT\"],\n",
    "                    mesh_object[\"fluid/SLAT_BKT\"],\n",
    "                    mesh_object[\"fluid/NAC\"],\n",
    "                    mesh_object[\"fluid/PYLON\"],\n",
    "                    mesh_object[\"fluid/IBFLAP\"],\n",
    "                    mesh_object[\"fluid/FSF\"],\n",
    "                    mesh_object[\"fluid/OBSLAT\"],\n",
    "                    mesh_object[\"fluid/WBF\"],\n",
    "                ],\n",
    "            ),\n",
    "            fl.Freestream(\n",
    "                surfaces=[\n",
    "                    mesh_object[\"fluid/Farfield\"],\n",
    "                    mesh_object[\"fluid/Inlet\"],\n",
    "                    mesh_object[\"fluid/Outlet\"],\n",
    "                ],\n",
    "            ),\n",
    "            fl.SlipWall(surfaces=mesh_object[\"fluid/Symmetry\"]),\n",
    "            fl.Fluid(\n",
    "                navier_stokes_solver=fl.NavierStokesSolver(\n",
    "                    absolute_tolerance=1e-10,\n",
    "                    relative_tolerance=1e-2,\n",
    "                    linear_solver=fl.LinearSolver(max_iterations=35),\n",
    "                    kappa_MUSCL=-1,\n",
    "                    numerical_dissipation_factor=1.0,\n",
    "                ),\n",
    "                turbulence_model_solver=turbulence_model_solver,\n",
    "            ),\n",
    "        ],\n",
    "        outputs=[volume_outputs, iso_surface],\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b50a0e11-94c5-4482-882d-a0696ee4bd28",
   "metadata": {},
   "source": [
    "## 6. Run case\n",
    "To run a case we need the previously defined `params` object to run the case in the project."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "bd48e36a-e7cc-4509-8b72-d7a75291c838",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-14T10:17:33.736627Z",
     "iopub.status.busy": "2026-07-14T10:17:33.736533Z",
     "iopub.status.idle": "2026-07-14T10:17:37.092425Z",
     "shell.execute_reply": "2026-07-14T10:17:37.091883Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[?25l"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\u001b[?25h"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[12:17:36] INFO: Successfully submitted:                                        \n",
      "                   type        = Case                                           \n",
      "                   name        = Unsteady DDES                                  \n",
      "                   id          = case-8c621b40-4cc1-4c51-8ead-c980ee27b67a      \n",
      "                   status      = pending                                        \n",
      "                   project id  = prj-5e29b718-4757-4d17-9f46-2648c428a44b       \n",
      "                                                                                \n"
     ]
    }
   ],
   "source": [
    "# `from_example` copies the example project at its original solver version\n",
    "# (release-25.8). Pin the current release so the DDES case runs on a solver\n",
    "# that matches the SimulationParams built above.\n",
    "case = project.run_case(\n",
    "    params=params,\n",
    "    name=\"Unsteady DDES\",\n",
    "    solver_version=\"release-25.10\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00b90e19-9600-46e6-92f0-4830b36b3157",
   "metadata": {},
   "source": [
    "![qCriterion HLPW](figures/animation_iso_hlpw.gif)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "flow360",
   "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.11.15"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
