{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "381b36b2",
   "metadata": {},
   "outputs": [],
   "source": [
    "from typing import Tuple, Union\n",
    "from collections import deque\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "from stable_baselines3 import PPO\n",
    "import pycuda.driver as cuda\n",
    "import pandas as pd\n",
    "import pickle\n",
    "import sys\n",
    "import os\n",
    "from gym_dummy import CustomEnv as DummyEnv\n",
    "\n",
    "current_dir = os.path.dirname(os.path.abspath(\"__file__\"))\n",
    "parent_dir = os.path.abspath(os.path.join(current_dir, os.pardir))\n",
    "sys.path.append(parent_dir)\n",
    "\n",
    "from CelerisLab import FlowField\n",
    "from CelerisLab import utils\n",
    "\n",
    "env_12 = DummyEnv(s_dim=12)\n",
    "env_14 = DummyEnv(s_dim=14)\n",
    "model_cloak_re100 = PPO.load(os.path.join(parent_dir, \"models\", \"old\", \"d1a3o12_re100.zip\"), env=env_12, device=\"cuda:0\")\n",
    "model_illusion = PPO.load(os.path.join(parent_dir, \"models\", \"250525\", \"d1a3o14_250525_imit_1L_2U_600S.zip\"), env=env_14, device=\"cuda:0\")\n",
    "model_illusion_075L = PPO.load(os.path.join(parent_dir, \"models\", \"250525\", \"d1a3o14_250525_imit_075L_2U_400S.zip\"), env=env_14, device=\"cuda:0\")\n",
    "model_illusion_15L = PPO.load(os.path.join(parent_dir, \"models\", \"250525\", \"d1a3o14_250525_imit_15L_2U.zip\"), env=env_14, device=\"cuda:0\")\n",
    "model_erase = PPO.load(os.path.join(parent_dir, \"models\", \"250729\", \"d1a3o12_250729_250326_erase_250804_20D_retrain2.zip\"), env=env_12, device=\"cuda:0\")\n",
    "model_cloak_lamb = PPO.load(os.path.join(parent_dir, \"models\", \"old\", \"vortex_lamb.zip\"), env=env_12, device=\"cuda:0\")\n",
    "model_cloak_taylor = PPO.load(os.path.join(parent_dir, \"models\", \"old\", \"vortex_taylor.zip\"), env=env_12, device=\"cuda:0\")\n",
    "\n",
    "model_cloak_re100.set_random_seed(0)\n",
    "model_illusion.set_random_seed(19)\n",
    "model_illusion_075L.set_random_seed(19)\n",
    "model_illusion_15L.set_random_seed(19)\n",
    "model_erase.set_random_seed(19)\n",
    "model_cloak_lamb.set_random_seed(0)\n",
    "model_cloak_taylor.set_random_seed(0)\n",
    "\n",
    "cuda.init()\n",
    "context = cuda.Device(0).make_context()\n",
    "config_cuda = utils.load_cuda_config(os.path.join(parent_dir, \"configs\", \"config_cuda.json\"))\n",
    "config_field = utils.load_flow_field_config(os.path.join(parent_dir, \"configs\", \"config_flowfield.json\"))\n",
    "\n",
    "L0 = 20\n",
    "U0 = config_field.velocity\n",
    "DATA_TYPE = np.float32\n",
    "CONV_LEN = 36\n",
    "\n",
    "context.push()\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "NX = flow_field.FIELD_SHAPE[0]\n",
    "NY = flow_field.FIELD_SHAPE[1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a276c1b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_field(flow_field, filename):\n",
    "    NX = flow_field.FIELD_SHAPE[0]\n",
    "    NY = flow_field.FIELD_SHAPE[1]\n",
    "    flow_field.get_ddf()\n",
    "    ddf_plot = flow_field.ddf.copy().reshape((9, NY, NX)).transpose(2, 1, 0)\n",
    "    flag_plot = flow_field.flag.copy().reshape((NY, NX)).transpose(1, 0)\n",
    "    ux = (ddf_plot[:, :, 1] + ddf_plot[:, :, 5] + ddf_plot[:, :, 8] - ddf_plot[:, :, 3] - ddf_plot[:, :, 6] - ddf_plot[:, :, 7]) / U0\n",
    "    uy = (ddf_plot[:, :, 2] + ddf_plot[:, :, 5] + ddf_plot[:, :, 6] - ddf_plot[:, :, 4] - ddf_plot[:, :, 7] - ddf_plot[:, :, 8]) / U0\n",
    "    with open(os.path.join(parent_dir, \"output\", filename), \"w\") as f:\n",
    "        f.write(\"Title= \\\"LBM 2D\\\"\\r\\n\")\n",
    "        f.write(\"VARIABLES= \\\"X\\\",\\\"Y\\\",\\\"flag\\\",\\\"U\\\",\\\"V\\\",\\r\\n\")\n",
    "        f.write(f\"ZONE T= \\\"BOX\\\",I= {NX},J= {NY},F=POINT\\r\\n\")\n",
    "        for j in range(NY):\n",
    "            for i in range(NX):\n",
    "                f.write(f\"{i},{j},{flag_plot[i, j]},{ux[i, j]},{uy[i, j]}\\r\\n\")\n",
    "\n",
    "class SimpleMeta:\n",
    "    pass\n",
    "\n",
    "def analyze_harmonics(states, n_harmonics):\n",
    "    N, D = states.shape\n",
    "    result = []\n",
    "    for d in range(D):\n",
    "        y = states[:, d]\n",
    "        fft_coef = np.fft.rfft(y)\n",
    "        freqs = np.fft.rfftfreq(N, d=1)\n",
    "        amps = 2 * np.abs(fft_coef) / N\n",
    "        phases = np.angle(fft_coef)\n",
    "        idx = np.argsort(amps[1:])[::-1][:n_harmonics] + 1\n",
    "        harmonics = {\n",
    "            'dc': np.real(fft_coef[0]) / N,\n",
    "            'amps': amps[idx],\n",
    "            'freqs': freqs[idx],\n",
    "            'phases': phases[idx]\n",
    "        }\n",
    "        result.append(harmonics)\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "751ba334",
   "metadata": {},
   "outputs": [],
   "source": [
    "target_states = np.empty((0, 6), dtype=DATA_TYPE)\n",
    "meta_cloak_steady = SimpleMeta()\n",
    "meta_cloak_dipole = SimpleMeta()\n",
    "meta_cloak_monopole = SimpleMeta()\n",
    "meta_illusion = SimpleMeta()\n",
    "meta_cloak_karman = SimpleMeta()\n",
    "\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(2*NX/U0), np.zeros(3, dtype=DATA_TYPE))\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(600, np.zeros(3, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:6]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_cloak_steady.target_states = np.mean(target_states, axis=0)\n",
    "\n",
    "# save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", \"target_steady.dat\"))\n",
    "\n",
    "target_states = np.empty((0, 6), dtype=DATA_TYPE)\n",
    "flow_field.get_ddf()\n",
    "flow_field.save_ddf()\n",
    "\n",
    "center_vor: Tuple[float, float, float] = (15 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.5*U0, 0, \"lamb\")\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(3, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:6]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_cloak_dipole.target_states = np.mean(target_states, axis=0)\n",
    "# flow_field.restore_ddf()\n",
    "# flow_field.apply_ddf()\n",
    "# flow_field.add_vortex(center_vor, L0 * 2, 0.5*U0, 0, \"lamb\")\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(3, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_lamb.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "\n",
    "target_states = np.empty((0, 6), dtype=DATA_TYPE)\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.03*U0, 0, \"taylor\")\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(3, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:6]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_cloak_monopole.target_states = np.mean(target_states, axis=0)\n",
    "# flow_field.restore_ddf()\n",
    "# flow_field.apply_ddf()\n",
    "# flow_field.add_vortex(center_vor, L0 * 2, 0.03*U0, 0, \"taylor\")\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(3, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_taylor.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "5a23560c",
   "metadata": {},
   "outputs": [],
   "source": [
    "target_states = np.empty((0, 6), dtype=DATA_TYPE)\n",
    "fifo_states = deque(maxlen=150)\n",
    "\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "center: Tuple[float, float, float] = (30 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "center: Tuple[float, float, float] = (31.3 * L0, (NY - 1) / 2 + 0.75 * L0, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "center: Tuple[float, float, float] = (31.3 * L0, (NY - 1) / 2 - 0.75 * L0, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(6, dtype=DATA_TYPE))\n",
    "flow_field.get_ddf()\n",
    "flow_field.save_ddf()\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(600, np.zeros(6, dtype=DATA_TYPE))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])\n",
    "\n",
    "temp_states = np.array(fifo_states)\n",
    "meta_illusion.force_norm_fact = 6 * np.max(np.abs(temp_states[:, 6:12]))\n",
    "\n",
    "meta_illusion.sens_deviation = np.zeros(6, dtype=DATA_TYPE)\n",
    "meta_illusion.sens_norm_fact = np.zeros(6, dtype=DATA_TYPE)\n",
    "for i in range(6):\n",
    "    meta_illusion.sens_deviation[i] = np.mean(temp_states[:, i])\n",
    "    meta_illusion.sens_norm_fact[i] = 5 * np.max(np.abs(temp_states[:, i] - meta_illusion.sens_deviation[i]))\n",
    "\n",
    "fifo_states = deque(maxlen=150)\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "flow_field.run(int(2*NX/U0), np.array([0.0, 0.0, 0.0, 0.0, -5*U0, 5*U0], dtype=DATA_TYPE))\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.5*U0, 0, \"lamb\")\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(6, dtype=DATA_TYPE))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])\n",
    "\n",
    "temp_states = np.array(fifo_states)\n",
    "meta_cloak_dipole.force_norm_fact = 6 * np.max(np.abs(temp_states[:, 6:12]))\n",
    "\n",
    "meta_cloak_dipole.sens_deviation = np.zeros(6, dtype=DATA_TYPE)\n",
    "meta_cloak_dipole.sens_norm_fact = np.zeros(6, dtype=DATA_TYPE)\n",
    "for i in range(6):\n",
    "    meta_cloak_dipole.sens_deviation[i] = np.mean(temp_states[:, i])\n",
    "    meta_cloak_dipole.sens_norm_fact[i] = 5 * np.max(np.abs(temp_states[:, i] - meta_cloak_dipole.sens_deviation[i]))\n",
    "\n",
    "fifo_states = deque(maxlen=150)\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "flow_field.run(int(2*NX/U0), np.array([0.0, 0.0, 0.0, 0.0, -5*U0, 5*U0], dtype=DATA_TYPE))\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.03*U0, 0, \"taylor\")\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(6, dtype=DATA_TYPE))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])\n",
    "\n",
    "temp_states = np.array(fifo_states)\n",
    "meta_cloak_monopole.force_norm_fact = 6 * np.max(np.abs(temp_states[:, 6:12]))\n",
    "\n",
    "meta_cloak_monopole.sens_deviation = np.zeros(6, dtype=DATA_TYPE)\n",
    "meta_cloak_monopole.sens_norm_fact = np.zeros(6, dtype=DATA_TYPE)\n",
    "for i in range(6):\n",
    "    meta_cloak_monopole.sens_deviation[i] = np.mean(temp_states[:, i])\n",
    "    meta_cloak_monopole.sens_norm_fact[i] = 5 * np.max(np.abs(temp_states[:, i] - meta_cloak_monopole.sens_deviation[i]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fc50665e",
   "metadata": {},
   "outputs": [],
   "source": [
    "fifo_states = deque(maxlen=150)\n",
    "\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "center: Tuple[float, float, float] = (10 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, 1*L0)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(7, dtype=DATA_TYPE))\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(7, dtype=DATA_TYPE))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])\n",
    "\n",
    "temp_states = np.array(fifo_states)\n",
    "meta_cloak_karman.force_norm_fact = 6 * np.max(np.abs(temp_states[:, 6:12]))\n",
    "\n",
    "meta_cloak_karman.sens_deviation = np.zeros(6, dtype=DATA_TYPE)\n",
    "meta_cloak_karman.sens_norm_fact = np.zeros(6, dtype=DATA_TYPE)\n",
    "for i in range(6):\n",
    "    meta_cloak_karman.sens_deviation[i] = np.mean(temp_states[:, i])\n",
    "    meta_cloak_karman.sens_norm_fact[i] = 5 * np.max(np.abs(temp_states[:, i] - meta_cloak_karman.sens_deviation[i]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "a5eee254",
   "metadata": {},
   "outputs": [],
   "source": [
    "del flow_field\n",
    "\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "center: Tuple[float, float, float] = (10 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, 1*L0)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(4, dtype=DATA_TYPE))\n",
    "\n",
    "target_states = np.empty((0, 6), dtype=DATA_TYPE)\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(4, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[2:8]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_cloak_karman.target_states = target_states\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(4, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_karman.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "feb7c904",
   "metadata": {},
   "outputs": [],
   "source": [
    "del flow_field\n",
    "\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "center: Tuple[float, float, float] = (31 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, 1*L0)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(4, dtype=DATA_TYPE))\n",
    "\n",
    "target_states = np.empty((0, 8), dtype=DATA_TYPE)\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(4, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:8]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_illusion.target_states_1L = target_states\n",
    "meta_illusion.target_harmonics_1L = analyze_harmonics(target_states, n_harmonics=5)\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(4, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_1L.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "573cda50",
   "metadata": {},
   "outputs": [],
   "source": [
    "del flow_field\n",
    "\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "center: Tuple[float, float, float] = (31 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, 0.75*L0)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(4, dtype=DATA_TYPE))\n",
    "\n",
    "target_states = np.empty((0, 8), dtype=DATA_TYPE)\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(400, np.zeros(4, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:8]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_illusion.target_states_075L = target_states\n",
    "meta_illusion.target_harmonics_075L = analyze_harmonics(target_states, n_harmonics=5)\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(4, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_075L.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "56f4be7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "del flow_field\n",
    "\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "center: Tuple[float, float, float] = (31 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, 1.5*L0)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(4, dtype=DATA_TYPE))\n",
    "\n",
    "target_states = np.empty((0, 8), dtype=DATA_TYPE)\n",
    "\n",
    "for i in range(150):\n",
    "    flow_field.run(800, np.zeros(4, dtype=DATA_TYPE))\n",
    "    new_state = flow_field.obs.copy()[0:8]\n",
    "    target_states = np.vstack((target_states, new_state))\n",
    "\n",
    "meta_illusion.target_states_15L = target_states\n",
    "meta_illusion.target_harmonics_15L = analyze_harmonics(target_states, n_harmonics=5)\n",
    "\n",
    "# for i in range(100):\n",
    "#     flow_field.run(1000, np.zeros(4, dtype=DATA_TYPE))\n",
    "#     file_name = f\"target_15L.{i:03d}\"\n",
    "#     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "d30ec201",
   "metadata": {},
   "outputs": [],
   "source": [
    "del flow_field\n",
    "\n",
    "flow_field = FlowField(config_field, config_cuda, device_id=0)\n",
    "center: Tuple[float, float, float] = (30 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "center: Tuple[float, float, float] = (31.3 * L0, (NY - 1) / 2 + 0.75 * L0, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "center: Tuple[float, float, float] = (31.3 * L0, (NY - 1) / 2 - 0.75 * L0, 0)\n",
    "flow_field.add_cylinder(center, L0 / 2)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 + 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "center: Tuple[float, float, float] = (40 * L0, (NY - 1) / 2 - 2 * L0, 0)\n",
    "flow_field.add_sensor(center, L0 / 4)\n",
    "flow_field.run(int(4*NX/U0), np.zeros(6, dtype=DATA_TYPE))\n",
    "\n",
    "flow_field.get_ddf()\n",
    "flow_field.save_ddf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "75309ab9",
   "metadata": {},
   "outputs": [],
   "source": [
    "# flow_field.restore_ddf()\n",
    "# flow_field.apply_ddf()\n",
    "fifo_states = deque(maxlen=150)\n",
    "for i in range(100):\n",
    "    flow_field.run(1000, np.zeros(6, dtype=DATA_TYPE))\n",
    "    file_name = f\"act_nc.{i:03d}\"\n",
    "    # save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "608f0eec",
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(75):\n",
    "    flow_field.run(1000, np.array([0.0, -5.1*U0, 5.1*U0, 0.0, 0.0, 0.0], dtype=DATA_TYPE))\n",
    "    file_name = f\"act_cloak_steady.{i:03d}\"\n",
    "    # save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "2999f0ee",
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_field.get_ddf()\n",
    "flow_field.save_ddf()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "9c4b02f5",
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.5*U0, 0, \"lamb\")\n",
    "\n",
    "obs = np.zeros(12, dtype=np.float32)\n",
    "for i in range(125):\n",
    "    action, _states = model_cloak_lamb.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(6, dtype=DATA_TYPE)\n",
    "    if i < 25:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/25) + temp_transition * (1 - i/25)\n",
    "    elif 45 <= i < 70:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (1-(i-45)/25) + temp_transition * ((i-45)/25)\n",
    "    elif i >= 70:\n",
    "        temp[0:3] = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "    else:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(800, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_cloak_dipole.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_cloak_dipole.sens_deviation) / meta_cloak_dipole.sens_norm_fact\n",
    "    obs = np.hstack([forces, sens])\n",
    "    file_name = f\"act_cloak_dipole.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "546e86c0",
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "flow_field.add_vortex(center_vor, L0 * 2, 0.03*U0, 0, \"taylor\")\n",
    "\n",
    "obs = np.zeros(12, dtype=np.float32)\n",
    "for i in range(125):\n",
    "    action, _states = model_cloak_taylor.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(6, dtype=DATA_TYPE)\n",
    "    if i < 20:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/20) + temp_transition * (1 - i/20)\n",
    "    elif 45 <= i < 70:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (1-(i-45)/25) + temp_transition * ((i-45)/25)\n",
    "    elif i >= 70:\n",
    "        temp[0:3] = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "    else:\n",
    "        temp_action = np.array(action*4 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(800, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_cloak_monopole.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_cloak_monopole.sens_deviation) / meta_cloak_monopole.sens_norm_fact\n",
    "    obs = np.hstack([forces, sens])\n",
    "    file_name = f\"act_cloak_monopole.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "    fifo_states.append(flow_field.obs.copy()[0:12])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "1f57113b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_target_states_at(t, harmonics):\n",
    "    t = np.asarray(t)\n",
    "    D = len(harmonics)\n",
    "    result = np.zeros((t.size, D), dtype=np.float32)\n",
    "    for d, h in enumerate(harmonics):\n",
    "        val = np.full(t.shape, h['dc'], dtype=np.float32)\n",
    "        for amp, freq, phase in zip(h['amps'], h['freqs'], h['phases']):\n",
    "            val += amp * np.cos(2 * np.pi * freq * t + phase)\n",
    "        result[:, d] = val\n",
    "    if result.shape[0] == 1:\n",
    "        return result[0]\n",
    "    return result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "a7999510",
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "\n",
    "obs = np.zeros(14, dtype=np.float32)\n",
    "for i in range(200):\n",
    "    action, _states = model_illusion.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(6, dtype=DATA_TYPE)\n",
    "    if i < 10:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/10) + temp_transition * (1 - i/10)\n",
    "    else:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(800, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_illusion.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_illusion.sens_deviation) / meta_illusion.sens_norm_fact\n",
    "    target_states = gen_target_states_at(i, meta_illusion.target_harmonics_1L)\n",
    "    target_cd = target_states[0] / meta_illusion.force_norm_fact\n",
    "    target_cl = target_states[1] / meta_illusion.force_norm_fact\n",
    "    obs = np.hstack([forces, sens, target_cd, target_cl])\n",
    "    file_name = f\"act_illusion_1L.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "    # if i % 2 == 0:\n",
    "    #     index = i // 2\n",
    "    #     file_name = f\"act_illusion_1L.{index:03d}\"\n",
    "    #     save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "65b31ee4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# flow_field.apply_ddf()\n",
    "\n",
    "obs = np.zeros(14, dtype=np.float32)\n",
    "for i in range(400):\n",
    "    action, _states = model_illusion_075L.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(6, dtype=DATA_TYPE)\n",
    "    if i < 20:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/10) + temp_transition * (1 - i/10)\n",
    "    else:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(400, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_illusion.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_illusion.sens_deviation) / meta_illusion.sens_norm_fact\n",
    "    target_states = gen_target_states_at(i, meta_illusion.target_harmonics_075L)\n",
    "    target_cd = target_states[0] / meta_illusion.force_norm_fact\n",
    "    target_cl = target_states[1] / meta_illusion.force_norm_fact\n",
    "    obs = np.hstack([forces, sens, target_cd, target_cl])\n",
    "    if i % 2 == 0:\n",
    "        index = i // 2\n",
    "        file_name = f\"act_illusion_075L.{index:03d}\"\n",
    "        save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "af362132",
   "metadata": {},
   "outputs": [],
   "source": [
    "# flow_field.apply_ddf()\n",
    "\n",
    "obs = np.zeros(14, dtype=np.float32)\n",
    "for i in range(200):\n",
    "    action, _states = model_illusion_15L.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(6, dtype=DATA_TYPE)\n",
    "    if i < 10:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/10) + temp_transition * (1 - i/10)\n",
    "    else:\n",
    "        temp_action = np.array(action*8 + [0, -2, 2], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(800, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_illusion.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_illusion.sens_deviation) / meta_illusion.sens_norm_fact\n",
    "    target_states = gen_target_states_at(i, meta_illusion.target_harmonics_15L)\n",
    "    target_cd = target_states[0] / meta_illusion.force_norm_fact\n",
    "    target_cl = target_states[1] / meta_illusion.force_norm_fact\n",
    "    obs = np.hstack([forces, sens, target_cd, target_cl])\n",
    "    file_name = f\"act_illusion_15L.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "c1eed77f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# center: Tuple[float, float, float] = (10 * L0, (NY - 1) / 2, 0)\n",
    "# flow_field.add_cylinder(center, 1*L0)\n",
    "flow_field.restore_ddf()\n",
    "flow_field.apply_ddf()\n",
    "\n",
    "obs = np.zeros(12, dtype=np.float32)\n",
    "for i in range(200):\n",
    "    action, _states = model_cloak_re100.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(7, dtype=DATA_TYPE)\n",
    "    if i < 10:\n",
    "        temp_action = np.array([0, 0, 0], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0.0, -5.1*U0, 5.1*U0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/10) + temp_transition * (1 - i/10)\n",
    "    else:\n",
    "        temp_action = np.array([0, 0, 0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(1000, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_cloak_karman.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_cloak_karman.sens_deviation) / meta_cloak_karman.sens_norm_fact\n",
    "    obs = np.hstack([forces, sens])\n",
    "    file_name = f\"act_karman_nc.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))\n",
    "\n",
    "for i in range(200):\n",
    "    action, _states = model_cloak_re100.predict(observation=obs, deterministic=True)\n",
    "    temp = np.zeros(7, dtype=DATA_TYPE)\n",
    "    if i < 10:\n",
    "        temp_action = np.array(action*8 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp_transition = np.array([0, 0, 0], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0 * (i/10) + temp_transition * (1 - i/10)\n",
    "    else:\n",
    "        temp_action = np.array(action*8 + [0, -4, 4], dtype=DATA_TYPE)\n",
    "        temp[0:3] = temp_action * U0\n",
    "    flow_field.run(800, temp)\n",
    "    states = np.array(flow_field.obs.copy()[0:12])\n",
    "    forces = states[0:6] / meta_cloak_karman.force_norm_fact\n",
    "    cd = (forces[0] + forces[2] + forces[4]) / 3\n",
    "    cl = (forces[1] + forces[3] + forces[5]) / 3\n",
    "    sens = (states[6:12] - meta_cloak_karman.sens_deviation) / meta_cloak_karman.sens_norm_fact\n",
    "    obs = np.hstack([forces, sens])\n",
    "    file_name = f\"act_karman_cloak.{i:03d}\"\n",
    "    save_field(flow_field, os.path.join(parent_dir, \"output\", \"250823\", \"data\", file_name))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c8cb1e8",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pycuda_3_10",
   "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.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
