diff --git a/examples/MITWindfarm_quickstart.ipynb b/examples/MITWindfarm_quickstart.ipynb index 250c671..ff2e901 100644 --- a/examples/MITWindfarm_quickstart.ipynb +++ b/examples/MITWindfarm_quickstart.ipynb @@ -20,13 +20,14 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 73, "metadata": {}, "outputs": [], "source": [ "from mitwindfarm import Area, AD, UnifiedAD, BEM, GaussianWakeModel, VariableKwGaussianWakeModel\n", "from mitwindfarm import Uniform, PowerLaw, Niayifar, Layout, GridLayout, Windfarm, Plotting\n", - "from MITRotor.ReferenceTurbines import IEA15MW" + "from MITRotor.ReferenceTurbines import IEA15MW\n", + "from MITRotor.Momentum import UnifiedMomentum" ] }, { @@ -38,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 74, "metadata": {}, "outputs": [], "source": [ @@ -57,7 +58,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "A `WindFarm` object has 5 optional parameters, each of which help determine its function. These parameters are the: `rotor_model`, `wake_model`, `superposition`, `base_windfield`, and `TIamb`. The first 4 arguments are objects/models. Their instantiation is discussed below. `TIamb` is the ambient turbulence intensity, which is simply a float value." + "A `WindFarm` object has 5 optional parameters, each of which help determine its function. These parameters are the: `rotor_model`, `wake_model`, `superposition`, `base_windfield`, and `TIamb`. The first 4 arguments are objects/models. Their instantiation is discussed below. `TIamb` is the ambient turbulence intensity, which is simply a float value.\n", + "\n", + "Beyond the standard windfarm, there is also a `CurledWindfarm` that implements the curled wake model. See `example_08_curled_windfarm.py` to see how to use that. It follows many similar principles to the rest of this guide." ] }, { @@ -71,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 75, "metadata": {}, "outputs": [], "source": [ @@ -108,7 +111,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 76, "metadata": {}, "outputs": [], "source": [ @@ -129,11 +132,11 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 77, "metadata": {}, "outputs": [], "source": [ - "rotor_bem = BEM(IEA15MW())" + "rotor_bem = BEM(IEA15MW(), momentum_model = UnifiedMomentum())" ] }, { @@ -151,16 +154,16 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Control setpoints: Ctprime = 2.00, yaw = 0.17\n", + "Control setpoints: Ctprime = 2.00, yaw = 0.17, tilt = 0.09\n", "Power coefficient: 0.58\n", - "Thrust coefficient: 0.88\n", + "Thrust coefficient: 0.87\n", "Axial induction: 0.33\n", "Far-wake streamwise velocity: 0.35\n", "Far-wake lateral velocity: -0.04\n", @@ -170,9 +173,9 @@ } ], "source": [ - "ad_solution = rotor_ad(x = 0, y = 0, z = 0, windfield = uniform_wind_field, Ctprime = 2, yaw = np.deg2rad(10))\n", + "ad_solution = rotor_ad(x = 0, y = 0, z = 0, windfield = uniform_wind_field, Ctprime = 2, yaw = np.deg2rad(10), tilt = np.deg2rad(5))\n", "\n", - "print(f\"Control setpoints: Ctprime = {ad_solution.Ctprime:2.2f}, yaw = {ad_solution.yaw:2.2f}\")\n", + "print(f\"Control setpoints: Ctprime = {ad_solution.Ctprime:2.2f}, yaw = {ad_solution.yaw:2.2f}, tilt = {ad_solution.tilt:2.2f}\")\n", "print(f\"Power coefficient: {ad_solution.Cp:2.2f}\")\n", "print(f\"Thrust coefficient: {ad_solution.Ct:2.2f}\")\n", "print(f\"Axial induction: {ad_solution.an:2.2f}\")\n", @@ -184,29 +187,29 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Control setpoints: Ctprime = 1.61, yaw = 0.17\n", - "Power coefficient: 0.49\n", - "Thrust coefficient: 0.78\n", - "Local thrust coefficient: 1.61\n", - "Axial induction: 0.27\n", - "Far-wake streamwise velocity: 0.44\n", - "Far-wake lateral velocity: -0.04\n", + "Control setpoints: Ctprime = 1.80, yaw = 0.17, tilt = 0.09\n", + "Power coefficient: 0.42\n", + "Thrust coefficient: 0.73\n", + "Local thrust coefficient: 1.80\n", + "Axial induction: 0.35\n", + "Far-wake streamwise velocity: 0.54\n", + "Far-wake lateral velocity: -0.03\n", "Rotor-effective wind speed: 1.00\n", "Wake turbulence intensity: 0.00\n" ] } ], "source": [ - "bem_solution = rotor_bem(x = 0, y = 0, z = 0, windfield = uniform_wind_field, pitch = 0, tsr = 9, yaw = np.deg2rad(10))\n", + "bem_solution = rotor_bem(x = 0, y = 0, z = 0, windfield = uniform_wind_field, pitch = 0, tsr = 9, yaw = np.deg2rad(10), tilt = np.deg2rad(5))\n", "\n", - "print(f\"Control setpoints: Ctprime = {bem_solution.Ctprime:2.2f}, yaw = {ad_solution.yaw:2.2f}\")\n", + "print(f\"Control setpoints: Ctprime = {bem_solution.Ctprime:2.2f}, yaw = {bem_solution.yaw:2.2f}, tilt = {bem_solution.tilt:2.2f}\")\n", "print(f\"Power coefficient: {bem_solution.Cp:2.2f}\")\n", "print(f\"Thrust coefficient: {bem_solution.Ct:2.2f}\")\n", "print(f\"Local thrust coefficient: {bem_solution.Ctprime:2.2f}\")\n", @@ -223,7 +226,7 @@ "source": [ "### Wake Model\n", "\n", - "Within the package, there is a `WakeModel` abstract class with two concrete types: the `GaussianWakeModel` and the `VariableKwGaussianWakeModel`. \n", + "Within the package, there is a `WakeModel` abstract class with two concrete types: the `GaussianWakeModel` and the `VariableKwGaussianWakeModel`. Note that the curled wake model is also implemented, but requires a different type of wind farm, a `CurledWindfarm`, due to different solving methods. See `example_08_curled_windfarm.py` for more information.\n", "\n", "The `GaussianWakeModel` has the following optional arguments (and default values): `sigma` (0.25), `kw` (0.07), `WATI_sigma_multiplier` (1.0), and `xmax` (100.0).\n", "\n", @@ -235,7 +238,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 80, "metadata": {}, "outputs": [], "source": [ @@ -261,7 +264,7 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 81, "metadata": {}, "outputs": [], "source": [ @@ -286,7 +289,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 82, "metadata": {}, "outputs": [], "source": [ @@ -320,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 83, "metadata": {}, "outputs": [], "source": [ @@ -334,7 +337,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 84, "metadata": {}, "outputs": [ { @@ -374,12 +377,12 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 85, "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGeCAYAAABGlgGHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAj/UlEQVR4nO3df2zV1f3H8dcH2t7ibK+i0l6gIAvID4FSikAv+4o/qrdICE2ajRCXMidETclENreUGEENXhbjD6bIjxnExTTgjwGbg167q1LcLVNamgBGNqahVW+LJnpvabZS2s/3D8N1d9LST3+d2/b5SE6wH865n3dvOOfz8tzPvdeybdsWAACAIcNMFwAAAIY2wggAADCKMAIAAIwijAAAAKMIIwAAwCjCCAAAMIowAgAAjCKMAAAAowgjAADAqCTTBXRFe3u7vvjiC6WlpcmyLNPlAACALrBtW01NTRo9erSGDetk/8N24MUXX7RnzJhhp6Wl2Wlpafb8+fPtAwcOdNj/5ZdftiXFNZfL5eSUtm3bdn19/fceh0aj0Wg02sBo9fX1nV7nHe2MjB07Vps2bdKkSZNk27ZeeeUVLV26VMeOHdONN954yTHp6ek6depU7Ofu7GykpaVJkurr65Wenu54PAAA6H/RaFRZWVmx63hHHIWRJUuWxP28ceNGbd26VUeOHOkwjFiWpczMTCenueRjSN8GG8IIAAADy+U2Irp9A2tbW5t2796t5uZm5eXlddjv3LlzGj9+vLKysrR06VKdPHnyso/d0tKiaDQa1wAAwODkOIwcP35cV155pVwul+6//37t3btX06ZNu2TfyZMna+fOndq/f79effVVtbe3y+v16rPPPuv0HH6/X263O9aysrKclgkAAAYIy7Zt28mA8+fPq66uTpFIRG+88YZeeuklHTp0qMNA8t9aW1s1depULV++XE888USH/VpaWtTS0hL7+eJrTpFIhJdpAAAYIKLRqNxu92Wv347f2puSkqKJEydKknJzc/Xhhx9q8+bN2r59+2XHJicnKycnR6dPn+60n8vlksvlcloaAAAYgHr8oWft7e1xuxidaWtr0/Hjx+XxeHp6WgAAMEg42hkpLS3VokWLNG7cODU1NamsrEzvvfeeAoGAJKm4uFhjxoyR3++XJD3++OOaP3++Jk6cqG+++UZPPfWUzpw5o5UrV/b+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xo4d2+Vxra2tmjp1qpYvX64nnnjikn1aWlrU0tIS+zkajSorK0uRSETp6endKRcAAPSzaDQqt9t92eu3o3tGLlq9erXeeustVVZWOgoikpScnKycnBydPn26wz4ul0sul6s7pQEAgAHG0cs0tm1r9erV2rt3r9555x1NmDDB8Qnb2tp0/PhxeTwex2MBAMDg42hnpKSkRGVlZdq/f7/S0tLU0NAgSXK73RoxYoQkqbi4WGPGjJHf75ckPf7445o/f74mTpyob775Rk899ZTOnDmjlStX9vKvAgAABiJHYWTr1q2SpFtuuSXu+Msvv6yf/exnkqS6ujoNG/bdhsvXX3+tVatWqaGhQVdffbVyc3MVCoU0bdq0nlUOAAAGhW7fwNqfunoDDAAASBxdvX7z3TQAAMAowggAADCKMAIAAIwijAAAAKMIIwAAwCjCCAAAMIowAgAAjCKMAAAAowgjAADAKMIIAAAwijACAACMIowAAACjCCMAAMAowggAADCKMAIAAIwijAAAAKMIIwAAwCjCCAAAMIowAgAAjCKMAAAAowgjAADAKMIIAAAwijACAACMIowAAACjCCMAAMAowggAADCKMAIAAIwijAAAAKMIIwAAwCjCCAAAMIowAgAAjCKMAAAAowgjAADAKMIIAAAwijACAACMIowAAACjCCMAAMAowggAADDKURjx+/266aablJaWplGjRqmwsFCnTp267LjXX39dU6ZMUWpqqmbMmKEDBw50u2AAADC4OAojhw4dUklJiY4cOaKKigq1trbqzjvvVHNzc4djQqGQli9frnvvvVfHjh1TYWGhCgsLdeLEiR4XDwAABj7Ltm27u4O//PJLjRo1SocOHdLNN998yT7Lli1Tc3Oz3nrrrdix+fPna9asWdq2bVuXzhONRuV2uxWJRJSent7dcgEAQD/q6vW7R/eMRCIRSdLIkSM77FNVVaX8/Py4Yz6fT1VVVR2OaWlpUTQajWsAAGBw6nYYaW9v15o1a7RgwQJNnz69w34NDQ3KyMiIO5aRkaGGhoYOx/j9frnd7ljLysrqbpkAACDBdTuMlJSU6MSJE9q9e3dv1iNJKi0tVSQSibX6+vpePwcAAEgMSd0ZtHr1ar311luqrKzU2LFjO+2bmZmpxsbGuGONjY3KzMzscIzL5ZLL5epOaQAAYIBxtDNi27ZWr16t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", "text/plain": [ "
" ] @@ -395,12 +398,12 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 86, "metadata": {}, "outputs": [ { "data": { - "image/png": "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9Pd///dx0003xW/8xm/EVVddFe973/vii1/8Yldm6fuw+NGPfhSnT5+Oq6++etH9V199dbz66qtdmorVZH5+Pu6777645ZZb4oYbbuj2OD3pxRdfjLe+9a0xNDQUn/rUp+LAgQNx3XXXdXusnvTYY4/FCy+8EFNTU90epedt3bo1HnnkkahUKrF///54+eWX40Mf+lDMzMx0e7Se82//9m+xf//+ePe73x3VajXuvvvu+MM//MP467/+647P0vFPN4V+s2vXrvjWt77l2u55vPe9742jR49Gs9mMv/u7v4udO3fGwYMHxcX/c+zYsbj33nvjqaeeiksuuaTb4/S8HTt2LPz35s2bY+vWrbFp06b4yle+Ep/85Ce7OFnvmZ+fj5tuuik++9nPRkTE+973vvjWt74VX/jCF2Lnzp0dnaXvz1i8/e1vj7Vr18Zrr7226P7XXnstrrnmmi5NxWpxzz33xNe+9rX4+te/Hhs2bOj2OD1r3bp18XM/93Nx4403xtTUVGzZsiX+7M/+rNtj9ZwjR47E8ePH45d+6ZdiYGAgBgYG4uDBg/Hnf/7nMTAwEKdPn+72iD3tbW97W7znPe+Jl156qduj9JxisfiGkP/5n//5rlw66vuwWLduXdx4441Rq9UW7pufn49areYaL8uW53ncc889ceDAgfinf/qneOc739ntkfrK/Px8zM7OdnuMnnPrrbfGiy++GEePHl243XTTTXHnnXfG0aNHY+3atd0esaedOHEivv/970exWOz2KD3nlltuecOfxP/rv/5rbNq0qeOzrIpLIffff3/s3Lkzbrrpprj55pvj85//fJw8eTLuuuuubo/WU06cOLGo9F9++eU4evRoXH755bFx48YuTtZ7du3aFY8++mh89atfjeHh4YXX6xQKhbj00ku7PF1v2b17d+zYsSM2btwYMzMz8eijj8YzzzwT1Wq126P1nOHh4Te8Tuctb3lLXHHFFV6/cxaf/vSn47bbbotNmzbFK6+8Env37o21a9fGHXfc0e3Res4f/dEfRalUis9+9rPxm7/5m/Hss8/Gww8/HA8//HDnh+n2n6Wk8hd/8Rf5xo0b83Xr1uU333xzfvjw4W6P1HO+/vWv5xHxhtvOnTu7PVrPOdt+ioj8y1/+crdH6zm/+7u/m2/atClft25dfuWVV+a33npr/o//+I/dHqtv+HPTc7v99tvzYrGYr1u3Lv/Zn/3Z/Pbbb89feumlbo/Vs/7hH/4hv+GGG/KhoaH82muvzR9++OGuzOFj0wGAZPr+NRYAQO8QFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMn8L+8sQAaDMymVAAAAAElFTkSuQmCC", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdVklEQVR4nO3db6ybdf3/8de1tadDOK0M3LjmzgYGBGHuCBtb1vkXJlcXsoBplBiMRzQmkIMyFxOyc8P13Chn3tCAZhl/VDDRZaDJQE3o5XIJ6zFlwrYsGRBRlMQTd22DxLRnJ+bQc87nd+PHOs+X7dCe8zm92u75SJrSrqefd64Yr2eu62rrGGOMAAAALFgQ9QAAAKBzEBYAAMAawgIAAFhDWAAAAGsICwAAYA1hAQAArCEsAACANYQFAACwJtbsBaempnT8+HF1d3fLcZxmLw8AAGbBGKPR0VEtW7ZMCxac/7hE08Pi+PHj6unpafayAADAgpGRES1fvvy8/970sOju7pb0/wdLJpPNXh4AAMxCpVJRT09PbT9+Pk0PizOnP5LJJGEBAECb+aDLGLh4EwAAWENYAAAAawgLAABgDWEBAACsISwAAIA1hAUAALCGsAAAoEOEYahcLqcwDCObgbAAAKBDhGGowcFBwgIAAHQGwgIAAFhDWAAAAGsICwAAYA1hAQBAhzDGTLuPAmEBAECbM8bI931ls1lJUjable/7kQQGYQEAQJs6ExTpdFqZTEau62pgYECu6yqTySidTjc9MAgLAADaUBAEtaCQpEKhoFKppHw+r1KppEKhIEm1wAiCoClzERYAALShYrEo6WxQeJ4nx3EkSY7jyPO8aYExPDzclLkc0+QTMJVKRalUSuVyWclksplLAwDQMarVqmKxWC0mZmKM0cTEhOLx+KzXq3f/HZv1CgAAIDKNRILjOHOKikbM6VTIzp075TiOtm7damkcAADQzmYdFq+88ooee+wxrV692uY8AACgjc0qLE6fPq27775bTzzxhC699FLbMwEAgDY1q7Do7+/X7bffrk2bNtmeBwAAtLGGL97cu3evjhw5oldeeaWu14+Pj2t8fLz2uFKpNLokAABoEw0dsRgZGdEDDzygX//611q0aFFdfzM0NKRUKlW79fT0zGpQAADQ+hr6Hotnn31WX/rSl7Rw4cLac5OTk3IcRwsWLND4+Pi0f5POfcSip6eH77EAAKCNzMv3WNx66606duzYtOfuueceXXfddXrwwQffFxWSlEgklEgkGlkGAAC0qYbCoru7W6tWrZr23MUXX6zLLrvsfc8DAIALD78VAgAArJnzV3q/+OKLFsYAAACdgCMWAADAGsICAABYQ1gAAABrCAsAAGANYQEAAKwhLAAAgDWEBQAAsIawAIAIhGGoXC6nMAyjHgWwirAAgAiEYajBwUHCAh2HsAAAANYQFgAAwBrCAgAAWENYAAAAawgLAIiAMWbaPdApCAsAaCJjjHzfVzablSRls1n5vk9goGMQFgDQBGeCIp1OK5PJyHVdDQwMyHVdZTIZpdNpAgMdgbAAgHkWBEEtKCSpUCioVCopn8+rVCqpUChIUi0wgiCIclxgTggLAJhnxWJR0tmg8DxPjuNIkhzHked50wJjeHg4slmBuXJMk4+7VSoVpVIplctlJZPJZi4NAJGoVquKxWK1mJiJMUYTExOKx+NNmAyoX73771gTZwKAC1IjkeA4DlGBtsapEAAAYA1hAQAArCEsAACANYQFAACwhrAAAADWEBYAAMAawgIAAFhDWAAAAGsICwAAYA1hAQAArCEsAACANYQFAACwhrAAAADWEBYAAMAawgIAAFhDWAAAAGsICwAAYA1hAQAArCEsgBmEYahcLqcwDKMeBQDaAmEBzCAMQw0ODhIWAFAnwgIAAFhDWAAAAGsICwAAYA1hAQAArCEsgBkYY6bdAwBmRlgA52CMke/7ymazkqRsNivf9wkMAPgAhAXwP84ERTqdViaTkeu6GhgYkOu6ymQySqfTBAYAzICwAN4TBEEtKCSpUCioVCopn8+rVCqpUChIUi0wgiCIclwAaEmEBfCeYrEo6WxQeJ4nx3EkSY7jyPO8aYExPDwc2awA0Koc0+RjupVKRalUSuVyWclksplLAzOqVquKxWK1mJiJMUYTExOKx+NNmAwAolfv/jvWxJmAltZIJDiOQ1QAwDlwKgQAAFhDWAAAAGsICwAAYA1hAQAArCEsAACANYQFAACwhrAAAADWEBYAAMAawgIAAFhDWAAAAGsICwAAYA1hAQAArCEsAACANYQFAACwhrAAAADWEBYAAMAawgIAAFjTMWERhqFyuZzCMIx6FAAALlgdFRaDg4OEBQAAEeqYsAAAANFrKCx2796t1atXK5lMKplM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r0cffVQf+tCH9Itf/GI+5gMAAG2kobB49913dfjwYW3atOnsGyxYoE2bNumll14659+Mj4+rUqlMu80HY8y0ewAA0HwNhcU777yjyclJLV26dNrzS5cu1YkTJ875N0NDQ0qlUrVbT0/P7Kc9B2OMfN9XNpuVJGWzWfm+T2AAABCBef9UyPbt21Uul2u3kZERK+97JijS6bQymYxc19XAwIBc11Umk1E6nSYwAABosobC4vLLL9fChQt18uTJac+fPHlSV1xxxTn/JpFIKJlMTrvNVRAEtaCQpEKhoFKppHw+r1KppEKhIEm1wAiCYM5rAgCAD9ZQWHR1dWnNmjXTdtRTU1MKgkAbNmywPtz5FItFSWeDwvM8OY4jSXIcR57nTQuM4eHhps0GAMCFzDENnit4+umn1dfXp8cee0zr1q3Tww8/rGeeeUZ//etf33ftxblUKhWlUimVy+VZH72oVquKxWK1mJiJMUYTExOKx+OzWgsAANS//441+sZ33XWX3n77bf3gBz/QiRMn9KlPfUqFQqGuqLClkUhwHIeoAACgSRo+YjFXNo5YAACA5qp3/81vhQAAAGsICwAAYA1hAQAArCEsAACANYQFAACwhrAAAADWEBYAAMAawgIAAFhDWAAAAGsa/krvuTrzRZ+VSqXZSwMAgFk6s9/+oC/sbnpYjI6OSpJ6enqavTQAAJij0dFRpVKp8/57038rZGpqSsePH1d3d3ddv05ar0qlop6eHo2MjPAbJB+AbVU/tlVj2F71Y1vVj21Vv/ncVsYYjY6OatmyZVqw4PxXUjT9iMWCBQu0fPnyeXv/ZDLJ//DqxLaqH9uqMWyv+rGt6se2qt98bauZjlScwcWbAADAGsICAABY0zFhkUgktGPHDiUSiahHaXlsq/qxrRrD9qof26p+bKv6tcK2avrFmwAAoHN1zBELAAAQPcICAABYQ1gAAABrCAsAAGBNx4TFrl27dOWVV2rRokVav369Xn755ahHajnFYlFbtmzRsmXL5DiOnn322ahHallDQ0O6+eab1d3drSVLlujOO+/UG2+8EfVYLWn37t1avXp17Qt5NmzYoOeffz7qsdrCzp075TiOtm7dGvUoLSmXy8lxnGm36667LuqxWta///1vfe1rX9Nll12miy66SJ/85Cd16NChps/REWHx9NNPa9u2bdqxY4eOHDmi3t5eeZ6nU6dORT1aSxkbG1Nvb6927doV9Sgt78CBA+rv79fBgwe1f/9+VatV3XbbbRobG4t6tJazfPly7dy5U4cPH9ahQ4d0yy236I477tBrr70W9Wgt7ZVXXtFjjz2m1atXRz1KS7vhhhsUhmHt9uc//znqkVrSf/7zH23cuFHxeFzPP/+8Xn/9df3oRz/SpZde2vxhTAdYt26d6e/vrz2enJw0y5YtM0NDQxFO1dokmX379kU9Rts4deqUkWQOHDgQ9Sht4dJLLzU/+9nPoh6jZY2OjpprrrnG7N+/33zuc58zDzzwQNQjtaQdO3aY3t7eqMdoCw8++KD59Kc/HfUYxhhj2v6IxbvvvqvDhw9r06ZNtecWLFigTZs26aWXXopwMnSScrksSVq8eHHEk7S2yclJ7d27V2NjY9qwYUPU47Ss/v5+3X777dP+fwvn9ve//13Lli3Txz72Md19993617/+FfVILel3v/ud1q5dqy9/+ctasmSJbrzxRj3xxBORzNL2YfHOO+9ocnJSS5cunfb80qVLdeLEiYimQieZmprS1q1btXHjRq1atSrqcVrSsWPHdMkllyiRSOjee+/Vvn37dP3110c9Vkvau3evjhw5oqGhoahHaXnr16/XU089pUKhoN27d+utt97SZz7zGY2OjkY9Wsv55z//qd27d+uaa66R7/u677779N3vfle//OUvmz5L03/dFGg3/f39evXVVzm3O4Nrr71WR48eVblc1m9/+1v19fXpwIEDxMX/MTIyogceeED79+/XokWLoh6n5W3evLn236tXr9b69eu1cuVKPfPMM/rWt74V4WStZ2pqSmvXrtVDDz0kSbrxxhv16quv6tFHH1VfX19TZ2n7IxaXX365Fi5cqJMnT057/uTJk7riiisimgqd4v7779cf/vAHvfDCC1q+fHnU47Ssrq4uXX311VqzZo2GhobU29urRx55JOqxWs7hw4d16tQp3XTTTYrFYorFYjpw4IB+8pOfKBaLaXJyMuoRW9qHP/xhffzjH9ebb74Z9Sgtx3Xd94X8Jz7xiUhOHbV9WHR1dWnNmjUKgqD23NTUlIIg4BwvZs0Yo/vvv1/79u3Tn/70J1111VVRj9RWpqamND4+HvUYLefWW2/VsWPHdPTo0dpt7dq1uvvuu3X06FEtXLgw6hFb2unTp/WPf/xDrutGPUrL2bhx4/s+Ev+3v/1NK1eubPosHXEqZNu2berr69PatWu1bt06PfzwwxobG9M999wT9Wgt5fTp09NK/6233tLRo0e1ePFirVixIsLJWk9/f7/27Nmj5557Tt3d3bXrdVKplC666KKIp2st27dv1+bNm7VixQqNjo5qz549evHFF+X7ftSjtZzu7u73Xadz8cUX67LLLuP6nXP4/ve/ry1btmjlypU6fvy4duzYoYULF+qrX/1q1KO1nO9973tKp9N66KGH9JWvfEUvv/yyHn/8cT3++OPNHybqj6XY8tOf/tSsWLHCdHV1mXXr1pmDBw9GPVLLeeGFF4yk9936+vqiHq3lnGs7STJPPvlk1KO1nG9+85tm5cqVpqury3zkIx8xt956q/njH/8Y9Vhtg4+bnt9dd91lXNc1XV1d5qMf/ai56667zJtvvhn1WC3r97//vVm1apVJJBLmuuuuM48//ngkc/Cz6QAAwJq2v8YCAAC0DsICAABYQ1gAAABrCAsAAGANYQEAAKwhLAAAgDWEBQAAsIawAAAA1hAWAADAGsICAABYQ1gAAABrCAsAAGDN/wMBrRt0LBoIPgAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -425,11 +428,11 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 87, "metadata": {}, "outputs": [], "source": [ - "bem_setpoints = [(0, 7, 0) for i in range(len(stag_grid_layout))]" + "bem_setpoints = [(0, 7, 0, 0) for i in range(len(stag_grid_layout))]" ] }, { @@ -448,12 +451,12 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 88, "metadata": {}, "outputs": [ { "data": { - "image/png": "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", + "image/png": "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", "text/plain": [ "
" ] @@ -479,7 +482,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "mitwindfarm-iuGKr_rh-py3.12", "language": "python", "name": "python3" }, @@ -493,7 +496,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.6" + "version": "3.12.11" } }, "nbformat": 4, diff --git a/examples/example_08_curled_windfarm.py b/examples/example_08_curled_windfarm.py new file mode 100644 index 0000000..efb4710 --- /dev/null +++ b/examples/example_08_curled_windfarm.py @@ -0,0 +1,99 @@ +from pathlib import Path + +import matplotlib.pyplot as plt +from mitwindfarm import Uniform, Layout, PowerLaw +from mitwindfarm.Plotting import plot_windfarm +from mitwindfarm.windfarm import Windfarm, CurledWindfarm +from mitwindfarm.Rotor import UnifiedAD_TI +import numpy as np +import time + +FIGDIR = Path(__file__).parent.parent / "fig" +FIGDIR.mkdir(exist_ok=True, parents=True) + + +def plot_example(powerlaw=False): + if powerlaw: + zhub = 1 # hub height in diameters + base_windfield = PowerLaw(Uref=1, zref=zhub, exp=0.11, TIamb=0.05) + else: # plot uniform inflow + zhub = 0 + base_windfield = Uniform(TIamb=0.05) # 5% ambient TI + + wf_curled = CurledWindfarm( + rotor_model=UnifiedAD_TI(), + base_windfield=base_windfield, + solver_kwargs=dict( + dy=1 / 10, + dz=1 / 10, + integrator="scipy_rk23", # see mitwindfarm.utils.integrate + k_model="k-l", # alternatives: "const", "2021" + verbose=False, + ), + ) + wf_gauss = Windfarm(TIamb=0.05) # 5% ambient TI, default model is Gaussian wake + layout = Layout([0, 5, 10], [0, 0.4, 0.8], [zhub, zhub, zhub]) # non-dim by diameter D + setpoints = [ # for UnifiedAD_TI() rotor, set points are (Ctprime, yaw, tilt) tuple pairs + (2, np.radians(30), np.radians(20)), + (2, np.radians(15), np.radians(10)), + (2, 0, 0), + ] # Example setpoints for three turbines + + # compute windfarm solutions (Cp) + wf_solutions = [] + for name, _wf in zip(["Curl", "Gauss"], [wf_curled, wf_gauss]): + time_st = time.time() + sol = _wf(layout, setpoints) + print(f"Windfarm solution for {name} in {time.time() - time_st:.2f} seconds") + wf_solutions.append((name, sol)) + + # plot the comparison: wind speed (streamwise slice) and power + fig1, axarr1 = plt.subplots( + figsize=(4 * len(wf_solutions), 6), + nrows=3, + ncols=len(wf_solutions), + sharex=True, + sharey="row", + height_ratios=(1, 1, 2), + ) + for axs, (name, sol) in zip(axarr1.T, wf_solutions): + plot_windfarm(sol, ax=axs[0], z = zhub, pad=2, axis=True) + y_plot_val = 0 + plot_windfarm(sol, ax=axs[1], y = y_plot_val, pad=2, axis=True) + axs[0].set_xlabel("$x/D$") + axs[1].set_xlabel("$x/D$") + axs[0].set_title(name + f" at z = {zhub}") + axs[1].set_title(name + f" at y = {y_plot_val}") + # plot power per turbine + axs[2].bar(layout.x, [r.Cp for r in sol.rotors], width=2) + if np.all(axs == (axarr1.T)[0]): # only label the first columns + axs[0].set_ylabel("$y/D$") + axs[1].set_ylabel("$z/D$") + axs[2].set_ylabel("$C_P$") + axs[2].set_xticks(layout.x) + axs[2].set_xticklabels(np.arange(len(layout.x)) + 1) + axs[2].set_xlabel("Turbine row") + + plt.savefig(FIGDIR / f"{Path(__file__).stem}1.png", bbox_inches="tight") + + fig2, axarr2 = plt.subplots( + figsize=(4 * len(wf_solutions), 4), + nrows=1, + ncols=len(wf_solutions), + sharex=True, + sharey="row", + ) + for axs, (name, sol) in zip(axarr2.T, wf_solutions): + # at first turbine's hub + x_plot_val = 4 + plot_windfarm(sol, ax=axs, x = x_plot_val, pad=2, axis=True) + axs.set_title(name + f" at x = {x_plot_val}") + axs.set_xlabel("$y/D$") + axs.set_ylabel("$z/D$") + + + plt.savefig(FIGDIR / f"{Path(__file__).stem}2.png", bbox_inches="tight") + +if __name__ == "__main__": + plot_example(powerlaw=False) + plt.close() diff --git a/examples/example_09_BEM_tilt_optimization.py b/examples/example_09_BEM_tilt_optimization.py index 62ed594..e513b53 100644 --- a/examples/example_09_BEM_tilt_optimization.py +++ b/examples/example_09_BEM_tilt_optimization.py @@ -8,7 +8,7 @@ from mitwindfarm.Rotor import BEM from MITRotor.ReferenceTurbines import IEA15MW from MITRotor.Momentum import UnifiedMomentum -# from rich import print +from rich import print import numpy as np FIGDIR = Path(__file__).parent.parent / "fig" diff --git a/examples/example_10_BEM_yaw_tilt.py b/examples/example_10_BEM_yaw_tilt.py index 3825389..8b51a66 100644 --- a/examples/example_10_BEM_yaw_tilt.py +++ b/examples/example_10_BEM_yaw_tilt.py @@ -9,7 +9,7 @@ from MITRotor.Momentum import UnifiedMomentum from MITRotor.ReferenceTurbines import IEA15MW from UnifiedMomentumModel.Utilities.Geometry import calc_eff_yaw -# from rich import print +from rich import print import numpy as np FIGDIR = Path(__file__).parent.parent / "fig" diff --git a/mitwindfarm/CurledWake.py b/mitwindfarm/CurledWake.py new file mode 100644 index 0000000..dd82458 --- /dev/null +++ b/mitwindfarm/CurledWake.py @@ -0,0 +1,972 @@ +""" +Curled wake model solver in MITWindfarm. +(Now in a separate file) + +Kirby Heck +2025 June 6 +""" + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Literal +from warnings import warn + +from numpy.typing import ArrayLike +import numpy as np +from scipy.signal import convolve2d +from scipy.interpolate import interpn, make_interp_spline + +from mitwindfarm.Windfield import Windfield +from mitwindfarm.Rotor import RotorSolution +from mitwindfarm.utils.integrate import ( + Integrator, + IntegrationException, + DomainExpansionRequest, +) +from UnifiedMomentumModel.Utilities.Geometry import calc_eff_yaw, eff_yaw_rotation, eff_yaw_inv_rotation +from mitwindfarm.utils.differentiate import second_der + + +class CurledWakeWindfield(Windfield): + """ + Windfield for the curled wake model. This wind field HAS a base windfield + which represents the base flow, and then adds turbines on top of the base + windfield. + + The CurledWakeWindfield is also the flow solver/forward marching method + for the Curled Wake Model. It does the following: + - Applies initial conditions + - Manages the domain size, expanding as necessary + - Manages turbulence models + - Marches the wind field (and possibly other fields: dk, dv, dw) forward + in space + """ + + def __init__( + self, + base_windfield: Windfield, + integrator: str = "scipy_rk45", + ivp_kwargs: dict = None, + dx: float = 0.1, + dy: float = 0.1, + dz: float = 0.1, + ybuff: float = 3, + zbuff: float = 2, + N_vortex: int = 10, + sigma_vortex: float = 0.2, + smooth_fact: float = 1, + k_model: Literal["const", "k-l"] = "const", + k_kwargs: dict = None, + ic_method: Literal["du", "fx"] = "du", + clip_u: float = 0.1, + use_r4: bool = True, + auto_expand: bool = True, + verbose: bool = False, + ): + """ + Initialize the wind field with specified parameters. + + Parameters: + - base_windfield: The base wind field to be used. + - integrator: IVP solver to be used for the wind field (default: "scipy_rk45"). + see integrate.Integrator for options. + - ivp_kwargs: Additional arguments for the integrator (default: None). + - dx: Grid spacing in the x-direction, non-dim (default: 0.2). + - dy: Grid spacing in the y-direction, non-dim (default: 0.1). + - dz: Grid spacing in the z-direction, non-dim (default: 0.1). + - ybuff: Buffer in the y-direction (default: 3). + - zbuff: Buffer in the z-direction (default: 2). + - smooth_fact: Smoothing factor for the initial condition stencil (default: 1). + - N_vortex: Number of vortices to use for the dv, dw initial conditions (default: 10). + - sigma_vortex: radius for the vortex de-singularization (default: 0.2). + - k_model: Turbulence model to use (default: "k-l"). + - k_kwargs: Additional arguments for the turbulence model (default: None). + - ic_method: Method for initial condition stamping (default: "du"). + NOTE: "fx" is experimental and only solves for EF marching. + - clip_u: Whether to clip the u-velocity to prevent negative values (default: 0.1). + Set to <= 0 to disable clipping + - use_r4: Whether to use the r4 rotor radius for initial conditions (default: True). + - auto_expand: Whether to automatically expand the domain when needed (default: True). + - verbose: Prints debug information if True (default: False). + """ + self.base_windfield = base_windfield + self.integrator = Integrator(integrator) + self.ivp_name = integrator + self.ivp_kwargs = ivp_kwargs if ivp_kwargs is not None else dict() + self.dx, self.dy, self.dz = dx, dy, dz + self.N_vortex = N_vortex + self.sigma_vortex = sigma_vortex + + # The following will get initialized later in check_grid_init() + self.grid = None # list of [x, y, z] axes + self.du = None # solved du-field + self.dv = None # solved dv-field + self.dw = None # solved dw-field + self.dk = None # solved k_wake field + + if "scipy" not in self.ivp_name: + self.ivp_kwargs.setdefault("dt", self.dx) + + self.ybuff = ybuff + self.zbuff = zbuff + + self.extra_fx = None + self.ic_method = ic_method # "fx" DOES NOT WORK - ONLY USE "du" + + self.clip_u = clip_u + self.use_r4 = use_r4 + self.auto_expand = auto_expand + + self.verbose = verbose + + # Turbulence modeling + self.k_model = k_model # turbulence model to use (default: "k-l") + self.k_kwargs = k_kwargs if k_kwargs is not None else {} + self.k_module = CurledTurbulenceModel.get_model( + self.k_model, curledwake=self, **self.k_kwargs + ) + + self.smooth_fact = smooth_fact # smoothing factor for the IC stencil + self.turbines = [] + + def wsp(self, x: ArrayLike, y: ArrayLike, z: ArrayLike) -> ArrayLike: + self.march_to(x=x, y=y, z=z) # check that the forward marching is sufficient + + x = np.asarray(x) + y = np.asarray(y) + z = np.asarray(z) + x, y, z = np.broadcast_arrays(x, y, z) + + wsp_base = self.base_windfield.wsp(x, y, z) + wsp_wakes = interpn( + (self.grid[0], self.grid[1], self.grid[2]), + self.du, + (x.ravel(), y.ravel(), z.ravel()), + method="linear", + bounds_error=False, + fill_value=0, + ).reshape(x.shape) + wsp = wsp_base + wsp_wakes + return wsp + + def TI(self, x: ArrayLike, y: ArrayLike, z: ArrayLike) -> ArrayLike: + self.march_to(x=x, y=y, z=z) # check that the forward marching is sufficient + + x = np.asarray(x) + y = np.asarray(y) + z = np.asarray(z) + x, y, z = np.broadcast_arrays(x, y, z) + + ti_base = self.base_windfield.TI(x, y, z) + wsp_base = self.base_windfield.wsp(x, y, z) + + k_wake = interpn( + (self.grid[0], self.grid[1], self.grid[2]), + self.dk, + (x.ravel(), y.ravel(), z.ravel()), + method="linear", + bounds_error=False, + fill_value=0, + ).reshape(x.shape) + wsp = self.wsp(x, y, z) + ti = np.sqrt((wsp_base * ti_base) ** 2 + 2 * k_wake / 3) / wsp + return ti + + def wdir(self, x: ArrayLike, y: ArrayLike, z: ArrayLike) -> ArrayLike: + # TODO: FIX + return self.base_windfield.wdir(x, y, z) + + def march_to(self, x: float, y: float, z: float) -> None: + """ + March the wind field to the specified coordinates. + + Parameters: + - x: x-coordinate. + - y: y-coordinate. + - z: z-coordinate. + """ + self.check_grid_init(x=x, y=y, z=z) # check if the grid is initialized + self._march(xmax=np.max(x)) + + def stamp_ic( + self, + rotor_solution: RotorSolution, + xt, + yt, + zt, + smooth_fact=None, + D=1, + ) -> None: + """ + Stamp the initial condition of the rotor solution into the wind field. + + Parameters: + - rotor_solution: The rotor solution to stamp into the wind field. + - smooth_fact: Smoothing factor for the initial condition stencil. + - D: Diameter of the rotor (default: 1). + """ + # first, add the turbine to the list of turbines + self.turbines.append(TurbineProperties(xt, yt, zt, D, rotor_solution)) + + # adjust grid bounds if necessary + self.adjust_grid_bounds(x=None, y=yt, z=zt, add_buffers=True) + + # streamwise velocity initial condition: + smooth_fact = self.smooth_fact if smooth_fact is None else smooth_fact + rotor = rotor_solution + r4 = ( + np.sqrt((1 - rotor.extra.an) / rotor.extra.u4) * D / 2 + if self.use_r4 + else D / 2 + ) + # calculate yaw angle in "yaw-only" frame + eff_yaw = calc_eff_yaw(rotor.yaw, rotor.tilt) + # create stencil + shape = ic_stencil( + self.grid[1], + self.grid[2], + yt, + zt, + smooth_fact=smooth_fact, + r4 = r4, + eff_yaw = eff_yaw, + yaw = rotor.yaw, + tilt = rotor.tilt, + ) + + # stamp the rotor solution into the wind field + # TODO: check du is negative? + delta_u = rotor.u4 - rotor.REWS # delta_u, adjusted by REWS + self.du[-1, ...] += shape * delta_u + + # dv, dw initial conditions: + if (rotor.yaw == 0) and (rotor.tilt == 0): + return # no additional dv, dw to stamp in for this turbine + + # TODO: Put this in a separate module + + # r-axis: clip edges to prevent singularities + d_yx = np.maximum(self.dy, self.dz) + # along z-axis in yaw-only frame (also the radial distance of each point from center in any frame) + r_i = np.linspace(-(D - d_yx) / 2, (D - d_yx) / 2, self.N_vortex) + # rotate points into yaw-and-tilt frame + _, y_i, z_i = eff_yaw_inv_rotation(np.zeros_like(r_i), np.zeros_like(r_i), r_i, eff_yaw, rotor.yaw, rotor.tilt) + # NOTE: rotor.Ct differs from Shapiro et al. (2018) definition - includes cos^2(eff_yaw) + Gamma_0 = 0.5 * D * rotor.REWS * rotor.Ct * np.sin(eff_yaw) + Gamma_i = ( + Gamma_0 * 4 * r_i / (self.N_vortex * D * np.sqrt(1 - (2 * r_i / D) ** 2)) + ) + + # generally, vortices can decay, so sigma should be a function of x # TODO + sigma = self.sigma_vortex * D + + # now we build the main summation, which is 3D (y, z, i) + yG, zG = np.meshgrid(self.grid[1], self.grid[2], indexing="ij") + yG = yG[..., None] + zG = zG[..., None] + + rsq = (yG - yt - y_i[None, None, :]) ** 2 + (zG - zt - z_i[None, None, :]) ** 2 # 3D grid variable + rsq = np.clip(rsq, 1e-8, None) # avoid singularities + + # put pieces together: + exponent = 1 - np.exp(-rsq / sigma**2) + summation = exponent / (2 * np.pi * rsq) * Gamma_i[None, None, :] + + # sum all vortices along last dim + v = np.sum(summation * (zG - zt - z_i[None, None, :]), axis=-1) + w = np.sum(summation * -(yG - yt - y_i[None, None, :]), axis=-1) + self.dv[-1, ...] += v # stamp in dv + self.dw[-1, ...] += w # stamp in dw + + def adjust_grid_bounds( + self, + x: ArrayLike = None, + y: ArrayLike = None, + z: ArrayLike = None, + add_buffers: bool = True, + ) -> None: + """ + Expand the dimensions of the wind field to accommodate wake + expansion and additional turbines. + + A buffer of xbuff, ybuff, zbuff will be applied to points checked. + + Parameters: + - x: x-coordinates, optional + - y: y-coordinates, optional + - z: z-coordinates, optional + - add_buffers: whether to add buffers to the grid (default: True) + """ + if self.grid is None: + raise AttributeError("Grid not initialized") + + # check and possibly expand grid with zero-padding + yax, zax = self.grid[1], self.grid[2] + ypad, zpad = (0, 0), (0, 0) + if y is not None: + y = np.atleast_1d(y) + ymin = np.min(y) - self.ybuff * add_buffers + ymax = np.max(y) + self.ybuff * add_buffers + ypad_lower = np.arange(yax[0] - self.dy, ymin - self.dy, -self.dy)[::-1] + ypad_upper = np.arange(yax[-1] + self.dy, ymax + self.dy, self.dy) + # update y-grid + self.grid[1] = np.concatenate([ypad_lower, yax, ypad_upper]) + ypad = (len(ypad_lower), len(ypad_upper)) + + if z is not None: + z = np.atleast_1d(z) + zmin = np.min(z) - self.zbuff * add_buffers + zmax = np.max(z) + self.zbuff * add_buffers + zpad_lower = np.arange(zax[0] - self.dz, zmin - self.dz, -self.dz)[::-1] + zpad_upper = np.arange(zax[-1] + self.dz, zmax + self.dz, self.dz) + # update z-grid + self.grid[2] = np.concatenate([zpad_lower, zax, zpad_upper]) + zpad = (len(zpad_lower), len(zpad_upper)) + + # # now we need to pad the du, dv, dw fields + self.du = np.pad(self.du, ((0, 0), ypad, zpad), mode="constant") + self.dv = np.pad(self.dv, ((0, 0), ypad, zpad), mode="constant") + self.dw = np.pad(self.dw, ((0, 0), ypad, zpad), mode="constant") + self.dk = np.pad(self.dk, ((0, 0), ypad, zpad), mode="constant") + self.extra_fx = np.pad(self.extra_fx, (ypad, zpad), mode="constant") + + def check_grid_init( + self, x: ArrayLike = None, y: ArrayLike = None, z: ArrayLike = None + ) -> None: + """Initializes self.grid if it doesn't exist.""" + if self.grid is None: + # Initialize the grid if it doesn't exist. Automatically add buffers + self.grid = [ + np.atleast_1d(x), + np.arange(-self.ybuff, self.ybuff + self.dy, self.dy) + y, + np.arange(-self.zbuff, self.zbuff + self.dz, self.dz) + z, + ] + + self.du = np.zeros(self.shape) + self.dv = np.zeros(self.shape) + self.dw = np.zeros(self.shape) + self.dk = np.zeros(self.shape) + self.extra_fx = np.zeros(self.shape[1:]) + + def _march(self, xmax) -> None: + """ + Forward marches delta_u and delta_k fields. + Can also expand to march delta_v and delta_w fields, + but for now these are constant in x (except when additional + yawed wakes are stamped in with initial conditions). + + Returns + - None (updates grid and self.du, self.dv, self.dw in place) + """ + if xmax <= np.max(self.grid[0]): + return # nothing to compute! + + # for now, _v and _w (2D slices of dv, dw) do not evolve in space + _v = self.dv[-1, ...] # last slice of dv + _w = self.dw[-1, ...] + y = self.grid[1] + z = self.grid[2] + ybnd, zbnd = (0, 0), (0, 0) # initialize variables for bound checking + + def _step(x, _state): + """ + Step for all functions d()/dx. + In the standard curled wake model, this is just Delta_u, but + in more advanced modeling (Klemmer and Howland, 2025), this also + marches the k_wake field forward simultaneously. + + Because some integrators (e.g., scipy) require a 1D array, we may + to reshape arrays to compute derivatives, then pack them back + into a flattened array. + """ + if np.any(np.isnan(_state)): + raise IntegrationException( + f"nan value encountered in state at x={x:.3f}", + ) + + # parse inputs from current state + _u, _k = self.k_module.unpack_inputs(_state) + _u = np.clip(_u, None, 0) # no positive velocity deficits... for now + + # ======== check state bounds for domain expansion ======== + if self.auto_expand: + check_yz = [] + check_yz.append(check_state_bounds(_u, thresh=1e-4)) + check_yz.append(check_state_bounds(_k, thresh=1e-6)) + if np.any([check_yz]): + # if any of the checks fail, we need to expand the domain along those dimensions + ybnd, zbnd = np.max(check_yz, axis=0) + raise DomainExpansionRequest( + f"Expanding domain at {x=:.2f}", expand_y=ybnd, expand_z=zbnd + ) + + # ========= assemble variables and fields ========= + # Full velocity fields for advection: + wsp = self.base_windfield.wsp(x, y[:, None], z[None, :]) + wdir = self.base_windfield.wdir(x, y[:, None], z[None, :]) + # compute k_base: assume TI = sqrt(2/3 k)/U + kb = (self.base_windfield.TI(x, y[:, None], z[None, :]) * wsp) ** 2 * 3 / 2 + u = _u + wsp * np.cos(wdir) + v = _v + wsp * np.sin(wdir) + w = _w + 0 + k = _k + kb + + if (self.clip_u > 0) and np.any(u < self.clip_u): + u = np.clip(u, self.clip_u, None) + + self.k_module.update_wake_fields(u, v, w, k, _u, _v, _w, _k) + nu_T = self.k_module.nu_T(x) + + # ============== du/dx computation ============== + # gradient fields of \Delta u: + dudy = np.gradient(_u, y, axis=0) + dudz = np.gradient(_u, z, axis=1) + d2udy2 = second_der(_u, self.dy, axis=0) + d2udz2 = second_der(_u, self.dz, axis=1) + dudx = (-v * dudy - w * dudz + nu_T * (d2udy2 + d2udz2) + self.extra_fx) / u + + self.extra_fx *= 0 # reset extra forces after they are used - TODO: remove + + # ============== dk/dx computation ============== + dkdx = self.k_module.compute_dkdx() + + ret = self.k_module.pack_outputs(dudx, dkdx) + return ret + + # use last slice as initial condition, turbulence model may update IC + ic = self.k_module.update_ic(self.du[-1, ...]) + + try: + x, ret = self.integrator( + _step, [self.grid[0].max(), xmax], ic, **self.ivp_kwargs + ) + except IntegrationException as e: + x = e.partial_t + ret = e.partial_u + if self.verbose: + print( + f"IntegrationException, exiting integration at x={max(x)}:\n\t", + e, + ) + except DomainExpansionRequest as e: + x = e.partial_t + ret = e.partial_u + ybnd = e.expand_y + zbnd = e.expand_z + # every time we get here, expand the expansion... + if np.any(ybnd): + self.ybuff += 1 + if np.any(zbnd): + self.zbuff += 1 + + if len(x) > 1: + # append and concatenate progress + du_new, dk_new = self.k_module.unpack_outputs(ret) + dv_new = np.repeat(self.dv[-1][None, ...], len(x) - 1, axis=0) + dw_new = np.repeat(self.dw[-1][None, ...], len(x) - 1, axis=0) + + self.du = np.concatenate([self.du, du_new[1:, ...]], axis=0) + self.dv = np.concatenate([self.dv, dv_new], axis=0) + self.dw = np.concatenate([self.dw, dw_new], axis=0) + self.dk = np.concatenate([self.dk, dk_new[1:, ...]], axis=0) + self.grid[0] = np.concatenate([self.grid[0], x[1:]]) + + # if we hit a DomainExpansionRequest, need to expand the grid and continue integrating + if np.any([ybnd, zbnd]): + if self.verbose: + print(f"Expanding grid at x={np.max(x):.2f} in y={ybnd} and z={zbnd}") + + self.adjust_grid_bounds( + y=[y[0] - ybnd[0] * self.ybuff, y[-1] + ybnd[1] * self.ybuff], + z=[z[0] - zbnd[0] * self.zbuff, z[-1] + zbnd[1] * self.zbuff], + add_buffers=False, + ) + self._march(xmax=xmax) # recursive call to continue marching + + @property + def shape(self) -> tuple[int, int, int]: + """ + Returns the shape of the grid. + """ + return (len(self.grid[0]), len(self.grid[1]), len(self.grid[2])) + + +@dataclass +class TurbineProperties: + """ + Class to hold turbine properties. + """ + + xt: float + yt: float + zt: float + D: float + rotor_solution: RotorSolution + + +# =========================================================================== +# ======================== TURBULENCE MODELING ============================== +# =========================================================================== + + +class CurledTurbulenceModel(ABC): + """ + Base class for the turbulence model in the curled wake model. + + Keeps track of all sub-classes with a self-registering factory. + """ + + _registry = {} + name: str # fill this in for each model + + def __init__(self, curledwake: CurledWakeWindfield): + self.curledwake = curledwake # link to the curled wake solver object + self.need_reshape = False + + def __init_subclass__(cls, **kwargs): + """ + This special method is called when a subclass is created. + It registers the subclass in the turbulence model registry. + """ + super().__init_subclass__(**kwargs) + if hasattr(cls, "name"): + cls._registry[cls.name] = cls + else: + raise ValueError(f"Subclass {cls.__name__} must define a 'name' attribute.") + + @classmethod + def get_model(cls, name: str, *args, **kwargs): + """ + Factory method to get an instance of a turbulence model. + """ + model_class = cls._registry.get(name) + if not model_class: + raise ValueError( + f"Unknown turbulence model: '{name}'. " + f"Available models: {list(cls._registry.keys())}" + ) + return model_class(*args, **kwargs) + + @abstractmethod + def nu_T(self, x): + """ + Returns nu_T, the eddy viscosity for the turbulence model + """ + ... + + def update_ic(self, ic): + """ + Update the initial condition for the turbulence model + """ + return ic + + def unpack_inputs(self, state): + """ + Unpack inputs for the forward marching u^n and possibly k^{n+1} + + Returns: + - du: wake deficit + - dk: k_wake field (default is 0) + """ + if state.ndim == 1: + self.need_reshape = True # we will need this in packing the outputs + state = state.reshape(self.curledwake.shape[1:]) + return state, np.zeros_like(state) + + def pack_outputs(self, dudx, dkdx): + """ + Pack outputs for the forward marching dudx and possibly dkdx + """ + if self.need_reshape: + dudx = dudx.flatten() + return dudx + + def unpack_outputs(self, ret): + """ + Unpack the output result of the forward marching + """ + return ret, np.zeros_like(ret) # default: no k_wake field + + def compute_dkdx(self): + """ + Computes the dk/dx term for the turbulence model. + """ + return None # by default, this is not needed + + def update_wake_fields(self, u, v, w, k, du, dv, dw, dk): + """ + Update the wake fields for the turbulence model. + """ + pass # by default, these are not needed + + def __repr__(self): + return f"CurledTurbulenceModel: {self.__class__.__name__}" + + +class CurledTurbulenceModel_const(CurledTurbulenceModel): + """ + Constant eddy viscosity model for the curled wake model. + """ + + name = "const" + + def __init__(self, curledwake, nu_T=1e-3, **kwargs): + """ + Initializes a constant eddy viscosity model with fixed model parameters. + """ + super().__init__(curledwake=curledwake) + self.nu_eff = nu_T + + def nu_T(self, x): + """ + Returns the constant eddy viscosity. + """ + return self.nu_eff + + +class CurledTurbulenceModel_2021(CurledTurbulenceModel): + """ + Curled wake turbulence model from Martínez-Tossas et al. (2021) WES paper + + Uses an ABL mixing length model proposed by Blackadar (1962) + """ + + name = "2021" + + def __init__( + self, + curledwake, + C: float = 4, + lam: float = None, + Ro: float = None, + kappa: float = 0.4, + ): + """ + Initializes the turbulence model. Note that all variables must + be non-dimensionalized or otherwise consistent with the + curled wake solver. + + Parameters: + - curledwake: The curled wake solver + - C: Constant for the turbulence model (default: 4) + - lam: Mixing length, non-dimensionalized (default: None) + - Ro: Turbine diameter-based rossby number G/(f_c * D) (default: None) + - kappa: von Karman constant (default: 0.4) + """ + super().__init__(curledwake=curledwake) + self.C = C + self.Ro = Ro + self.kappa = kappa + if Ro is not None: + self.lam = 0.00027 * Ro # lam/D + elif lam is not None: + self.lam = lam + else: + raise AttributeError( + "Either `lam` or `Ro` must be provided to the turbulence model." + ) + + def nu_T(self, x): + """ + Computes Eq. 13 in Martínez-Tossas et al. (2021) + + Note that as the baseflow may vary as a function of x, y, z, + dU/dz is computed at the current x, y, z locations. + """ + yg, zg = np.meshgrid( + self.curledwake.grid[1], self.curledwake.grid[2], indexing="ij" + ) + U = self.curledwake.base_windfield.wsp(x, yg, zg) + dUdz = np.gradient(U, self.curledwake.dz, axis=-1) + lmix = self.kappa * zg / (1 + self.kappa * zg / self.lam) + lmix = np.clip(lmix, 1e-2, None) # mixing length must be non-negative + + return self.C * lmix**2 * np.abs(dUdz) + + +class CurledTurbulenceModel_kl(CurledTurbulenceModel): + """ + Class for the k-l turbulence model in the curled wake model. + + See Klemmer and Howland, JRSE (2025) for details and derivation. + """ + + name = "k-l" + + def __init__(self, curledwake, C_nu=0.04, C_k1=1, C_k2=1): + """ + Initializes a k-l turbulence model with fixed model parameters. + + Parameters + - curledwake: The curled wake solver + - C_nu: Constant for the eddy viscosity (default: 0.04) + - C_k1: transport term coefficient (default: 1) + - C_k2: dissipation term coefficient (default: 1) + """ + super().__init__(curledwake=curledwake) + self.C_nu = C_nu + self.C_k1 = C_k1 + self.C_k2 = C_k2 + self.nu_T_cached = 0 + self.dk = None # we will save this field from parsing inputs + self.u, self.v, self.w, self.k = None, None, None, None + self.du, self.dv, self.dw, self.dk = None, None, None, None + + def update_ic(self, ic): + """ + Stacks the k_wake field to the initial condition for the forward marching. + """ + return np.stack([ic, self.curledwake.dk[-1, ...]], axis=-1) + + def update_wake_fields(self, u, v, w, k, du, dv, dw, dk): + """ + Update the wake fields for the turbulence model. + """ + self.u = u + self.v = v + self.w = w + self.k = k + self.du = du + self.dv = dv + self.dw = dw + self.dk = dk + + def nu_T(self, x): + """ + Computes Eq. 6 in Klemmer and Howland (2025) + """ + lmix = interpolate_lmix(self.du, self.curledwake.grid[1])[:, None] + if np.any(lmix <= 0): + raise IntegrationException("lmix is non-positive") + + heaviside = get_heaviside(x, self.curledwake.grid[1], self.curledwake.turbines)[ + :, None + ] + self.nu_T_cached = self.C_nu * ( + (1 - heaviside) * np.sqrt(np.clip(self.k - self.dk, 0, None)) * 1 + + heaviside * np.sqrt(np.clip(self.k, 0, None)) * lmix + ) + return self.nu_T_cached + + def compute_dkdx(self): + """ + Computes the dk/dx term for the turbulence model. + """ + y = self.curledwake.grid[1] + z = self.curledwake.grid[2] + nu_T = self.nu_T_cached + lmix = interpolate_lmix(self.du, y)[:, None] + if np.any(lmix <= 0): + raise IntegrationException("lmix is non-positive") + + # transport equation for k_wake, written in parabolic form: + dkdx = ( + -self.v * np.gradient(self.dk, y, axis=0) + - self.w * np.gradient(self.dk, z, axis=1) + + nu_T + * ( + np.gradient(self.du, y, axis=0) * np.gradient(self.u, y, axis=0) + + np.gradient(self.du, z, axis=1) * np.gradient(self.u, z, axis=1) + ) + + self.C_k1 # pull out of gradient as C_k1 is constant + * ( + np.gradient(nu_T * np.gradient(self.dk, y, axis=0), y, axis=0) + + np.gradient(nu_T * np.gradient(self.dk, z, axis=1), z, axis=1) + ) + # need np.clip for the sqrt here + - self.C_k2 * (np.clip(self.dk, 0, None) ** (3 / 2) / lmix) + ) / self.u + return dkdx + + def unpack_inputs(self, state): + """ + Returns: + - du: wake deficit + - dk: k_wake field + """ + if state.ndim == 1: + self.need_reshape = True # we will need this in packing the outputs + state = state.reshape(self.curledwake.shape[1:] + (2,)) + + self.dk = state[..., 1] + return state[..., 0], state[..., 1] + + def pack_outputs(self, dudx, dkdx): + """ + Pack outputs for the forward marching dudx, dkdx + """ + ret = np.stack([dudx, dkdx], axis=-1) + if self.need_reshape: + return ret.flatten() + else: + return ret + + def unpack_outputs(self, ret): + """ + Unpack the output result of the forward marching + """ + return ret[..., 0], ret[..., 1] + + +def check_state_bounds(state, thresh=1e-4): + """ + Check values of 2D array `state` at the boundaries to see + if a domain expansion is needed. + """ + max_y = np.max(abs(state[[0, -1], :]), axis=1) + max_z = np.max(abs(state[:, [0, -1]]), axis=0) + + expand_y = max_y > thresh + expand_z = max_z > thresh + + return expand_y, expand_z + + +def ic_stencil(y, z, yt, zt, smooth_fact=1, r4 = 0.5, eff_yaw = 0.0, yaw = 0.0, tilt = 0.0) -> np.ndarray: + """ + Stencil for turbine initial condition. This is a 2D Gaussian kernel that is + convolved with an indicator function. + + Parameters: + - y: y-coordinates. + - z: z-coordinates. + - smooth_fact: Smoothing factor for the initial condition stencil. + - ay: Width of the stencil in the y-direction (default: 0.5). + - az: Width of the stencil in the z-direction (default: ay). + """ + yG, zG = np.meshgrid(y, z, indexing="ij") + dy = y[1] - y[0] + dz = z[1] - z[0] # assume these are equally spaced axes + kernel_y = np.arange(-10, 11)[:, None] * dy + kernel_z = np.arange(-10, 11)[None, :] * dz + + # determine if points are in the turbine when rotated into the "yaw-only" frame + ay, az = r4 * np.cos(eff_yaw), r4 + _, yvals, z_vals = eff_yaw_rotation(np.ones_like(yG), yG - yt, zG - zt, eff_yaw, yaw, tilt) + turb = ((yvals / ay) ** 2 + (z_vals / az) ** 2) < 1.0 + # create gaussian in the ground frame + gauss = np.exp( + -(kernel_y**2 + kernel_z**2) / (np.sqrt(dy * dz) * smooth_fact) ** 2 / 2 + ) + gauss /= np.sum(gauss) # make sure this is normalized to 1 + return convolve2d(turb, gauss, "same") # smooth edges of gaussian + + +def get_wake_bounds_y(du, thresh=0.05, relative=True): + """ + Parse wake bounds from the 2D du field, returns indices for + all crossings of threshold `thresh` from the wake profile in y. + + Parameters: + - du: 2D array of delta_u + - thresh: threshold for wake bounds + - relative: whether to use a threshold relative to max(abs(du)) + + Returns: + - ycross: array of y-crossings, arranged as [2 x N] array of (lower, upper) index pairs + """ + + du_y = np.max(abs(du), axis=1) + + _thresh = thresh * np.max(du_y) if relative else thresh + + ycross_lower = np.where((du_y[:-1] < _thresh) & (du_y[1:] >= _thresh))[0] + ycross_upper = np.where((du_y[:-1] > _thresh) & (du_y[1:] <= _thresh))[0] + ycross = np.vstack([ycross_lower, ycross_upper]) + + return ycross + + +def get_wake_bounds_z(du, thresh=0.05, relative=True): + """ + Parse wake bounds from the 2D du field, returns indices for + all crossings of threshold `thresh` from the wake profile in z. + + Parameters: + - du: 2D array of delta_u + - thresh: threshold for wake bounds + - relative: whether to use a threshold relative to max(abs(du)) + + Returns: + - zcross: array of z-crossings, arranged as [2 x N] array of (lower, upper) index pairs + """ + + du_z = np.max(abs(du), axis=0) + + _thresh = thresh * np.max(abs(du)) if relative else thresh + + zcross_lower = np.where((du_z[:-1] < _thresh) & (du_z[1:] >= _thresh))[0] + zcross_upper = np.where((du_z[:-1] > _thresh) & (du_z[1:] <= _thresh))[0] + zcross = np.vstack([zcross_lower, zcross_upper]) + + return zcross + + +def interpolate_lmix(du, y, k=0, fill_value=1.0, max_value=None, pad=True): + """ + Interpolates the mixing length scale from the du field. + + Parameters: + - du: 2D array of delta_u + - y: y-coordinates + - k: interpolation order (default: 0, nearest neighbor) + - fill_value: value to fill if no bounds are found (default: 1.0) + - max_value: maximum value for the mixing length scale (default: None, no limit) + - pad: whether to pad the du field with zeros (default: True) + + Returns: + - lmix: 1D array of mixing length scale + """ + if np.any(np.isnan(du)): + raise ValueError("du contains NaN values") + + if pad: + # zero-pad wake_bnds to ensure it goes to zero on both sides + wake_bnds = get_wake_bounds_y(np.pad(du, (1, 1), mode="constant")) + y_pad = np.pad(y, (1, 1), mode="edge") + y_bounds = y_pad[wake_bnds] + else: + wake_bnds = get_wake_bounds_y(du) + y_bounds = y[wake_bnds] + + if y_bounds.size == 0: + return np.full_like(y, fill_value) + + y_mean = np.mean(y_bounds, axis=0) + y_width = np.diff(y_bounds, axis=0).flatten() + f = make_interp_spline( + y_mean, + y_width, + k=k, # nearest interpolation + ) + if max_value is None: + return f(y) + else: + return np.clip(f(y), None, max_value) + + +def get_heaviside(x, yax, turbines, default_x0=1): + """ + Computes the heaviside function, which is 1 in the far-wake and 0 in the near-wake. + """ + ret = np.zeros_like(yax) + for t in turbines: + try: + x0 = t.rotor_solution.extra.x0 + if x0 == np.inf: + x0 = default_x0 + except AttributeError: + x0 = default_x0 + + if x >= t.xt and x < t.xt + x0: + # yids = (yax >= (t.yt - t.D/2)) & (yax <= (t.yt + t.D/2)) + # ret[yids] = 1 + ret += np.exp(-((yax - t.yt) ** 2) / 2 / (t.D / 2) ** 2) + + ret = np.clip(ret, 0, 1) + + return 1 - ret + + +if __name__ == "__main__": + pass diff --git a/mitwindfarm/Rotor.py b/mitwindfarm/Rotor.py index f3fb73a..bdd3356 100644 --- a/mitwindfarm/Rotor.py +++ b/mitwindfarm/Rotor.py @@ -219,6 +219,69 @@ def __call__(self, x: float, y: float, z: float, windfield: Windfield, Ctprime, ) +class UnifiedAD_TI(UnifiedAD): + """ + Same as UnifiedAD but also accounts for a possible TI dependence + """ + + def __init__(self, rotor_grid=None, beta=0.1403, alpha=2.32, couple_x0=False): + """ + Initialize the UnifiedAD rotor model with the given axial induction factor. + + Parameters: + - beta (float): Axial induction factor (default is 0.1403). + - alpha (float): Turbulence intensity factor (default is 2.32, from Bastankhah and Porté-Agel 2016). + - couple_x0 (bool): If True, couples the x0 parameter to the pressure equation. Default is False. + """ + super().__init__(rotor_grid=rotor_grid) + if couple_x0: + self._model = UnifiedMomentumTI(beta=beta, alpha=alpha) + else: + self._model = UnifiedMomentumTI_x0(beta=beta, alpha=alpha) + + def __call__( + self, x: float, y: float, z: float, windfield: Windfield, Ctprime, yaw = 0, tilt = 0, + ) -> RotorSolution: + """ + Calculate the rotor solution for given Ctprime and yaw inputs. + + Parameters: + - Ctprime (float): Thrust coefficient including the effect of yaw. + - yaw (float): Yaw angle of the rotor. + + Returns: + RotorSolution: The calculated rotor solution. + """ + + # Get the points over rotor to be sampled in windfield + xs_loc, ys_loc, zs_loc = self.rotor_grid.grid_points() + xs_glob, ys_glob, zs_glob = xs_loc + x, ys_loc + y, zs_loc + z + + # sample windfield and calculate rotor effective wind speed + Us = windfield.wsp(xs_glob, ys_glob, zs_glob) + TIs = windfield.TI(xs_glob, ys_glob, zs_glob) + + REWS = self.rotor_grid.average(Us) + RETI = np.sqrt(self.rotor_grid.average(TIs**2)) + sol = self._model(Ctprime, yaw = yaw, tilt = tilt, TI=RETI) + + # rotor solution is normalised by REWS. Convert normalisation to U_inf and return + return RotorSolution( + yaw, + sol.Cp * REWS**3, + sol.Ct * REWS**2, + sol.Ctprime, + sol.an * REWS, + sol.u4 * REWS, + sol.v4 * REWS, + REWS, + tilt = tilt, + w4 = sol.w4 * REWS, + TI=RETI, + extra=sol, + ) + + class BEM(Rotor): """ Blade Element Momentum (BEM) rotor model. Note: MITRotor is formulated in @@ -392,3 +455,108 @@ def __call__(self, x: float, y: float, z: float, windfield: Windfield, yaw = 0, TI=RETI, extra=None ) + + +# Custom momentum models - move to UnifiedMomentum later on +class UnifiedMomentumTI_x0(UnifiedMomentum): + """ + Here, the influence of TI on x0 is decoupled from the + other near-wake equations. + """ + + def __init__( + self, beta=0.1403, alpha=2.32, cached=True, v4_correction=1.0, **kwargs + ): + super().__init__( + beta=beta, cached=cached, v4_correction=v4_correction, **kwargs + ) + self.alpha = alpha + + def post_process(self, result, Ctprime, yaw = 0, tilt = 0, TI = 0, **kwargs): + a, u4, v4, _x0, dp = result.x + x0 = ( + np.cos(self.eff_yaw) + / 4 + * (1 + u4) + * np.sqrt((1 - a) * np.cos(self.eff_yaw) / (1 + u4)) + / (self.beta * np.abs(1 - u4) / 2 + self.alpha * TI) + ) # re-compute x0 with TI influence decoupled + result.x = (a, u4, v4, x0, dp) + return super().post_process(result, Ctprime, yaw = yaw, tilt = tilt, **kwargs) + + +class UnifiedMomentumTI(UnifiedMomentum): + """ + Extends the Unified Momentum Model to include a TI dependence + as described in Bastankhah and Porté-Agel (2016). + """ + def __init__(self, beta=0.1403, alpha=2.32, **kwargs): + super().__init__(beta=beta, **kwargs) + self.alpha = alpha + + def residual( + self, x: np.ndarray, Ctprime: float, TI: float = 0, **kwargs + ): + """ + Returns the residuals of the Unified Momentum Model for the fixed point + iteration. The equations referred to in this function are from the + associated paper. + """ + an, u4, v4, x0, dp = x + if type(Ctprime) is float and Ctprime == 0: + return 0 - an, 1 - u4, 0 - v4, 100 - x0, 0 - dp + + p_g = self._nonlinear_pressure(Ctprime, self.eff_yaw, an, x0) + + # Eq. 4 - Near wake length in residual form, includes alpha term. + e_x0 = ( + np.cos(self.eff_yaw) + / 4 + * (1 + u4) + * np.sqrt((1 - an) * np.cos(self.eff_yaw) / (1 + u4)) + / (self.beta * np.abs(1 - u4) / 2 + self.alpha * TI) + ) - x0 + + # Eq. 1 - Rotor-normal induction in residual form. + e_an = ( + 1 + - np.sqrt( + -dp / (0.5 * Ctprime * np.cos(self.eff_yaw) ** 2) + + (1 - u4**2 - v4**2) / (Ctprime * np.cos(self.eff_yaw) ** 2) + ) + ) - an + + # Eq. 2 - Streamwise outlet velocity in residual form. + e_u4 = ( + -(1 / 4) * Ctprime * (1 - an) * np.cos(self.eff_yaw) ** 2 + + (1 / 2) + + (1 / 2) + * np.sqrt( + (1 / 2 * Ctprime * (1 - an) * np.cos(self.eff_yaw) ** 2 - 1) ** 2 - (4 * dp) + ) + ) - u4 + + # Eq. 3 - Lateral outlet velocity in residual form. + e_v4 = ( + -self.v4_correction + * (1 / 4) + * Ctprime + * (1 - an) ** 2 + * np.sin(self.eff_yaw) + * np.cos(self.eff_yaw) ** 2 + - v4 + ) + + # Eq. 5 - Outlet pressure drop in residual form. + e_dp = ( + ( + -(1 / (2 * np.pi)) + * Ctprime + * (1 - an) ** 2 + * np.cos(self.eff_yaw) ** 2 + * np.arctan(1 / (2 * x0)) + ) + + p_g + ) - dp + + return e_an, e_u4, e_v4, e_x0, e_dp \ No newline at end of file diff --git a/mitwindfarm/utils/differentiate.py b/mitwindfarm/utils/differentiate.py new file mode 100644 index 0000000..e2611b3 --- /dev/null +++ b/mitwindfarm/utils/differentiate.py @@ -0,0 +1,152 @@ +""" +Differentiation module + +Kirby Heck +2025 May 05 +""" + +import numpy as np +import warnings + + +def second_der( + arr, + dxi=None, + axis=-1, +): + """ + Computes the second derivative using second-order finite differences. + + Uses central differences for the interior and second-order forward/backward + differences for the boundaries. + + [Written by Gemini 2.5 Pro] + + Args: + arr (np.ndarray): Input array. + axis (int): The axis along which the derivative is taken. Default is -1. + dxi (float or array-like, optional): Spacing between points. + If None, spacing is assumed to be 1.0. + If a single float, it's used for the specified axis. + If an array-like, its length must be 1 or match arr.ndim. If it + matches arr.ndim, the spacing for the specified axis is used. + + Returns: + np.ndarray: The computed second derivative, same shape as arr. + + Raises: + ValueError: If dxi is array-like and its length doesn't match arr.ndim. + ValueError: If the array size along the specified axis is less than 2. + (Second-order boundaries require >= 4 points). + """ + arr = np.asarray(arr) + ndim = arr.ndim + # Ensure axis is positive for easier handling + positive_axis = axis if axis >= 0 else ndim + axis + if not (0 <= positive_axis < ndim): + raise np.AxisError(f"Invalid axis {axis} for array with {ndim} dimensions.") + + n = arr.shape[positive_axis] + + if dxi is None: + dx = 1.0 + else: + dxi = np.atleast_1d(dxi) + if len(dxi) == 1: + dx = float(dxi[0]) # Ensure float division + elif len(dxi) == ndim: + dx = float(dxi[positive_axis]) + else: + raise ValueError( + f"Length of dxi ({len(dxi)}) must be 1 or match the number of dimensions in arr ({ndim})." + ) + + if dx == 0: + raise ValueError("Spacing dx cannot be zero.") + + dx_sq = dx * dx + + # Initialize the result array + d2f_dx2 = np.zeros_like(arr, dtype=np.result_type(arr, dx)) # Match type + + # Handle edge cases for small arrays where second-order boundaries are not possible + if n < 2: + raise ValueError( + f"Array size {n} along axis {positive_axis} is too small to compute second derivative." + ) + elif n == 2: + # Cannot compute 2nd derivative meaningfully with only 2 points using these methods. + # np.gradient would give 0 for the 2nd derivative. Let's return 0. + warnings.warn( + f"Array size {n} along axis {positive_axis} is small; returning zeros for second derivative.", + stacklevel=2, + ) + return d2f_dx2 # Already zeros + elif n == 3: + # Can only compute central difference for the middle point + # Boundaries are problematic for 2nd order. + # Let's compute the middle point and leave boundaries as 0, with a warning. + warnings.warn( + f"Array size {n} along axis {positive_axis} is small; using central difference for interior point only, boundaries set to zero.", + stacklevel=2, + ) + f_im1 = np.take(arr, 0, axis=positive_axis) + f_i = np.take(arr, 1, axis=positive_axis) + f_ip1 = np.take(arr, 2, axis=positive_axis) + center_val = (f_ip1 - 2 * f_i + f_im1) / dx_sq + # Place the result in the correct slice of the output array + result_slice = [slice(None)] * ndim + result_slice[positive_axis] = 1 + d2f_dx2[tuple(result_slice)] = center_val + return d2f_dx2 + + # --- Main computation for n >= 4 --- + + # Interior points (central difference) + f_im1 = np.take(arr, np.arange(0, n - 2), axis=positive_axis) + f_i = np.take(arr, np.arange(1, n - 1), axis=positive_axis) + f_ip1 = np.take(arr, np.arange(2, n - 0), axis=positive_axis) + interior_val = (f_ip1 - 2 * f_i + f_im1) / dx_sq + + # Place the result in the correct slice of the output array + result_slice_interior = [slice(None)] * ndim + result_slice_interior[positive_axis] = slice(1, n - 1) + d2f_dx2[tuple(result_slice_interior)] = interior_val + + # Boundary point 0 (forward difference O(dx^2)) + # [2*f0 - 5*f1 + 4*f2 - f3] / dx^2 + f0 = np.take(arr, 0, axis=positive_axis) + f1 = np.take(arr, 1, axis=positive_axis) + f2 = np.take(arr, 2, axis=positive_axis) + f3 = np.take(arr, 3, axis=positive_axis) + start_val = (2 * f0 - 5 * f1 + 4 * f2 - f3) / dx_sq + + result_slice_start = [slice(None)] * ndim + result_slice_start[positive_axis] = 0 + d2f_dx2[tuple(result_slice_start)] = start_val + + # Boundary point N-1 (backward difference O(dx^2)) + # [2*f_{N-1} - 5*f_{N-2} + 4*f_{N-3} - f_{N-4}] / dx^2 + f_n1 = np.take(arr, n - 1, axis=positive_axis) + f_n2 = np.take(arr, n - 2, axis=positive_axis) + f_n3 = np.take(arr, n - 3, axis=positive_axis) + f_n4 = np.take(arr, n - 4, axis=positive_axis) + end_val = (2 * f_n1 - 5 * f_n2 + 4 * f_n3 - f_n4) / dx_sq + + result_slice_end = [slice(None)] * ndim + result_slice_end[positive_axis] = n - 1 + d2f_dx2[tuple(result_slice_end)] = end_val + + return d2f_dx2 + + +if __name__ == "__main__": + x = np.linspace(0, 2 * np.pi, 200, endpoint=False) + y = np.sin(x) * x + d2y_analytical = 2 * np.cos(x) - x * np.sin(x) + d2y = second_der(y, dxi=np.diff(x)[0], axis=0) + d2y_numpy = np.gradient(np.gradient(y, x), x) + print("Error in numerical vs analytical second derivative:") + print(np.max(np.abs(d2y - d2y_analytical))) + print("Numpy second derivative error:") + print(np.max(np.abs(d2y_numpy - d2y_analytical))) diff --git a/mitwindfarm/utils/integrate.py b/mitwindfarm/utils/integrate.py new file mode 100644 index 0000000..4d010ce --- /dev/null +++ b/mitwindfarm/utils/integrate.py @@ -0,0 +1,306 @@ +""" +IVP integration methods for Curled Wake Modeling + +Kirby Heck +2025 May 05 +""" + +import numpy as np +from scipy import integrate # import solve_ivp as solve_ivp_scipy + + +def rk4_step(t_n, u_n, dudt, dt): + """ + Computes the next timestep of u_n given the finite difference function du/dt + with a 4-stage, 4th order accurate Runge-Kutta method. + + Parameters + ---------- + t_n : float + time for time step n + u_n : array-like + condition at time step n + dudt : function + function du/dt(t, u) + dt : float + time step + + Returns u_(n+1) + """ + k1 = dt * dudt(t_n, u_n) + k2 = dt * dudt(t_n + dt / 2, u_n + k1 / 2) + k3 = dt * dudt(t_n + dt / 2, u_n + k2 / 2) + k4 = dt * dudt(t_n + dt, u_n + k3) + + u_n1 = u_n + 1 / 6 * (k1 + 2 * k2 + 2 * k3 + k4) + return u_n1 + + +def EF_step(t_n, u_n, dudt, dt): + """ + Simple forward Euler stepping scheme. + + Parameters + ---------- + t_n : float + time for time step n + u_n : array-like + condition at time step n + dudt : function + function du/dt(t, u) + dt : float + time step + + Returns u_(n+1) + """ + u_n1 = u_n + dt * dudt(t_n, u_n) + return u_n1 + + +METHODS = { + f"scipy_{key}".lower(): val for key, val in integrate._ivp.ivp.METHODS.items() +} +STEPS = { + "rk4": rk4_step, + "ef": EF_step, +} + + +def solve_ivp(dudt, T, u0, dt=0.1, f=rk4_step, end_exact=True, **kwargs): + """ + General integration function which calls a step function multiple times depending + on the parabolic integration strategy. + + Checks for two specific exceptions: + - IntegrationException: raised when the integration fails at a specific time step. + - DomainExpansionRequest: raised when the integration requests a domain expansion. + + Parameters + ---------- + dudt : function + Evolution function du/dt(t, u, ...) + T : (2, ) + Time range + u0 : array-like + Initial condition of values + dt : float + Time step + f : function + Integration stepper function (e.g. RK4, EF, etc.) + + Returns + ------- + t : (Nt, ) vector + Time vector + u(t) : (Nt, ...) array-like + Solution to the parabolic ODE. + """ + t = [] + ut = [] + + u_n = u0 # initial condition + t_n = T[0] + + ut.append(u_n) + t.append(t_n) + + keep_going = True + while keep_going: + # update timestep + t_n1 = t_n + dt + if t_n1 > T[1]: + if end_exact: + dt = T[1] - t_n # adjust the last step to end exactly at T[1] + if dt == 0: + break # avoid zero step size, not sure exactly how we get here + t_n1 = T[1] + keep_going = False + else: + break + + try: + u_n1 = f(t_n, u_n, dudt, dt) + except IntegrationException as e: + # re-raise with additional state information + raise IntegrationException( + "Integration failed at time step.", + partial_t=np.array(t), # save integration up to this point + partial_u=np.array(ut), + ) from e + except DomainExpansionRequest as e: + # re-raise with additional state information + e.partial_t = np.array(t) # save integration up to this point + e.partial_u = np.array(ut) + raise e + # raise DomainExpansionRequest( + # "Domain expansion requested during integration.", + # partial_t=np.array(t), + # partial_u=np.array(ut), + # expand_y=e.expand_y, + # expand_z=e.expand_z, + # ) from e + + # save solution + ut.append(u_n1) + t.append(t_n1) + + # update: + u_n = u_n1 + t_n = t_n1 + + return np.array(t), np.array(ut) + + +def solve_ivp_interrupt(dudt, T, u0, f=METHODS["scipy_rk45"], **options): + """ + Uses scipy's stepper functions but overrides the + default scipy solve_ivp to allow for interruptions and + custom Exception handling. + """ + + t0, tf = map(float, T) + try: + # for initializing the solver calls `dudt`, so this must be caught as well + solver = f(dudt, t0, np.atleast_1d(u0), t_bound=tf, **options) + except (DomainExpansionRequest, IntegrationException) as e: + e.partial_t, e.partial_u = [T[0]], u0 + raise e + + t = [solver.t] + ut = [solver.y] + + while solver.status == "running": + try: + message = solver.step() + except (DomainExpansionRequest, IntegrationException) as e: + e.partial_t = np.array(t) + e.partial_u = np.array(ut) + raise e + except Exception as e: + raise IntegrationException( + f"Integration failed during step: {e}", + partial_t=np.array(t), # save integration up to this point + partial_u=np.array(ut), + extra=str(e), + ) from e + + # append solution + t.append(solver.t) + ut.append(solver.y) + + return np.array(t), np.array(ut) + + +class Integrator: + def __init__(self, scheme="rk4"): + self.use_scipy = False + self.use_scipy_method = False + + if callable(scheme): + self.step_fn = scheme + + elif scheme.lower() in METHODS: + self.use_scipy = True + self.use_scipy_method = True + self.step_fn = METHODS[scheme.lower()] + + elif scheme.lower() in STEPS: + self.step_fn = STEPS[scheme.lower()] + + elif scheme.lower() == "scipy": + self.use_scipy = True + + else: + avail = ", ".join(sorted(METHODS.keys()) + list(STEPS.keys()) + ["scipy"]) + raise ValueError( + f"Unknown integration scheme: {scheme}, choose from {avail}" + ) + + def __call__(self, dudt, T, u0, **kwargs): + """Calls the integrator function""" + + if self.use_scipy_method: + _kwargs = dict(rtol=1e-4, max_step=0.5) # helps with stability + _kwargs.update(kwargs) + u0 = np.atleast_1d(u0) + shape = u0.shape + try: + t, y = solve_ivp_interrupt( + dudt, T, u0.flatten(), f=self.step_fn, **kwargs + ) + return t, y.reshape(len(t), *shape).squeeze() + except (DomainExpansionRequest, IntegrationException) as e: + e.partial_u = e.partial_u.reshape(len(e.partial_t), *shape).squeeze() + raise e + + elif self.use_scipy: + raise NotImplementedError( + "scipy deprecated because it does not allow for exception handling" + ) + + else: + return solve_ivp(dudt, T, u0, f=self.step_fn, **kwargs) + + +class IntegrationException(Exception): + """Custom exception for integration failures.""" + + def __init__( + self, + message, + partial_t=None, + partial_u=None, + extra=None, + ): + super().__init__(message) + self.partial_t = partial_t + self.partial_u = partial_u + self.message = message + self.extra = extra + + def __str__(self): + return self.message + + +class DomainExpansionRequest(Exception): + """Custom exception to signal a request for domain expansion.""" + + def __init__( + self, + message, + partial_t=None, + partial_u=None, + expand_y=None, + expand_z=None, + extra=None, + ): + super().__init__(message) + self.partial_t = partial_t + self.partial_u = partial_u + self.expand_y = expand_y + self.expand_z = expand_z + self.message = message + self.extra = extra + + def __str__(self): + return self.message + + +if __name__ == "__main__": + # Example usage: + # Define a simple ODE: du/dt = -u + def dudt(t, u): + # if u < 5e-2: + # raise IntegrationException("less than threshold") + return -u + + integrator = Integrator("scipy_rk45") + try: + time, solution = integrator(dudt, (0, 10), 1, dt=0.1, end_exact=True) + except IntegrationException as e: + time, solution = e.partial_t, e.partial_u + print("Time:", time[-1]) + print("Solution:", solution) + print(solution.squeeze().shape) + # Compare with analytical solution e^(-t) + print("Analytical Solution:", np.exp(-time)) diff --git a/mitwindfarm/windfarm.py b/mitwindfarm/windfarm.py index 779a090..976b322 100644 --- a/mitwindfarm/windfarm.py +++ b/mitwindfarm/windfarm.py @@ -7,6 +7,7 @@ from .Rotor import Rotor, AD, RotorSolution from .Windfield import Windfield, Uniform from .Wake import WakeModel, Wake, GaussianWakeModel +from .CurledWake import CurledWakeWindfield from .Superposition import Superposition, Niayifar @@ -142,3 +143,56 @@ def from_partial(self, partial: PartialWindfarmSolution) -> WindfarmSolution: def from_dict(self, partial: dict) -> WindfarmSolution: return self.from_partial(PartialWindfarmSolution.from_dict(partial)) + + +class CurledWindfarm(Windfarm): + """ + Curled Wake model wind farm solver. This solver needs a slightly different + __call__ method because there are no "wakes" or "wake superposition" in the + Curled Wake model. The wind farm is solved in a single step by numerically + integrating a parabolic PDE. + + Follows the general framework of Martínez-Tossas et al. (2019, 2021). + """ + + def __init__( + self, + rotor_model: Optional[Rotor] = None, + base_windfield: Optional[Windfield] = None, + TIamb: float = None, + solver_kwargs: Optional[dict] = None, + ): + """ + Initializes the CurledWindFarm. + + Note that TIamb is unused. Instead, ensure that the `base_windfield` + includes ambient turbulence. + """ + self.rotor_model = AD() if rotor_model is None else rotor_model + self.base_windfield = ( + Uniform(TIamb=TIamb) if base_windfield is None else base_windfield + ) + self.TIamb = TIamb + self.solver_kwargs = dict() if solver_kwargs is None else solver_kwargs + + def __call__( + self, layout: Layout, setpoints: list[tuple[float, ...]] + ) -> WindfarmSolution: + """ + Solves for the rotor solutions in the wind farm layout, marching + the CurledWakeWindfield to each rotor location as necessary. + """ + # this function has to: 1) arrange rotors to march downstream, 2) initialize the CurledWakeWindfield, 3) solve, 4) aggregate results + N = layout.x.size + wakes = N * [None] # this just remains as [None, ...] in CWM + rotor_solutions = N * [None] + + windfield = CurledWakeWindfield(self.base_windfield, **self.solver_kwargs) + + for i, (x, y, z) in layout.iter_downstream(): + windfield.march_to(x=x, y=y, z=z) # march to the next rotor location, extrapolating where necessary + rotor_solutions[i] = self.rotor_model(x, y, z, windfield, *setpoints[i]) + rotor_solutions[i].idx = i + windfield.stamp_ic(rotor_solutions[i], x, y, z) # stamp the rotor solution into the windfield + + return WindfarmSolution(layout, setpoints, rotor_solutions, wakes, windfield) diff --git a/tests/test_curled_wake.py b/tests/test_curled_wake.py new file mode 100644 index 0000000..305c0e1 --- /dev/null +++ b/tests/test_curled_wake.py @@ -0,0 +1,115 @@ +from pytest import fixture, mark, approx +import numpy as np +from mitwindfarm import Uniform, Layout +from mitwindfarm.windfarm import Windfarm, CurledWindfarm +from mitwindfarm.Rotor import UnifiedAD_TI, UnifiedAD +from UnifiedMomentumModel.Utilities.Geometry import calc_eff_yaw, eff_yaw_inv_rotation +from scipy.ndimage import rotate + +def get_curled_windfarm(couple_x0 = False, TIamb = 0.05): + base_windfield = Uniform(TIamb=TIamb) + wf_curled = CurledWindfarm( + rotor_model=UnifiedAD_TI(couple_x0 = couple_x0), + base_windfield=base_windfield, + solver_kwargs=dict( + dy=1/10, + dz=1/10, + integrator="scipy_rk23", # see mitwindfarm.utils.integrate + k_model="k-l", # alternatives: "const", "2021" + verbose=False, + ), + ) + + xturb, yturb, zturb = [0], [0], [0] + layout = Layout(xturb, yturb, zturb) + return wf_curled, layout + +def get_gaussian_windfarm(): + base_windfield = Uniform() + wf = Windfarm( + rotor_model=UnifiedAD(), + base_windfield=base_windfield, + ) + return wf + +def get_yaws_tilts(val): + # create three sets of setpoints with same effective angle, one with just yaw, + # one with just tilt, and one with yaw and tilt. + yaw3 = np.radians(val) + tilt3 = np.radians(val) + eff_yaw = calc_eff_yaw(yaw3, tilt3) + yaws, tilts = [eff_yaw, 0, yaw3], [0, eff_yaw, tilt3] + return yaws, tilts + + + +# test that wake is the same stamp rotated for different combinations of yaw and tilt +def test_wake_shape_rotation(): + wf_curled, layout = get_curled_windfarm() + # get grid points + pad, res = 2, 100 + ylim = (np.min(layout.y) - pad, np.max(layout.y) + pad) + zlim = (np.min(layout.z) - pad, np.max(layout.z) + pad) + _y, _z = np.linspace(*ylim, res), np.linspace(*zlim, res) + ymesh, zmesh = np.meshgrid(_y, _z) + # get solutions to all set point combos + wsp_list = [] + ctprime = 1.33 + xval = 5 #D + yaws, tilts = get_yaws_tilts(20) + for yaw, tilt in zip(yaws, tilts): + setpoints = [(ctprime, yaw, tilt)] + sol = wf_curled(layout, setpoints) + wsp = sol.windfield.wsp(np.full_like(ymesh, xval), ymesh, zmesh) + wsp_list.append(wsp) + + # rotate solutions to be in "yaw-only" frame + rotated_yaw = rotate(wsp_list[0], 0, reshape=False, order=1, mode='constant', cval=1) + rotated_tilt = rotate(wsp_list[1], -90, reshape=False, order=1, mode='constant', cval=1) + rotated_yaw_and_tilt = rotate(wsp_list[2], -45, reshape=False, order=1, mode='constant', cval=1) + + # check that there is less than 5% difference between each rotated dataset compared to yaw simulation + assert(np.allclose(rotated_yaw, wsp_list[0], atol = 0.05 * np.min(wsp_list[0]))) + assert(np.allclose(rotated_tilt, wsp_list[0], atol = 0.05 * np.min(wsp_list[0]))) + assert(np.allclose(rotated_yaw_and_tilt, wsp_list[0], atol = 0.05 * np.min(wsp_list[0]))) + +def test_TI_rotor_equivalence(): + wf_curled_TI, layout = get_curled_windfarm(couple_x0 = False, TIamb = 0) + wf_curled_TI_couple, _ = get_curled_windfarm(couple_x0 = True, TIamb = 0) + wf = get_gaussian_windfarm() + yaws, tilts = get_yaws_tilts(20) + ctprime = 1.33 + for yaw, tilt in zip(yaws, tilts): + setpoints = [(ctprime, yaw, tilt)] + sol1 = wf_curled_TI(layout, setpoints) + sol2 = wf_curled_TI_couple(layout, setpoints) + sol3 = wf(layout, setpoints) + # ensure that without TI, the new UMM models (with TI adjustments) are equivalent + assert sol1.rotors[0].u4 == sol2.rotors[0].u4 == sol3.rotors[0].u4 + assert sol1.rotors[0].Cp == sol2.rotors[0].Cp == sol3.rotors[0].Cp + # need to use "is-close" since values are re-calculated and could be off by rounding + assert np.isclose(sol1.rotors[0].extra.dp_NL, sol3.rotors[0].extra.dp_NL) + assert np.isclose(sol1.rotors[0].extra.x0, sol3.rotors[0].extra.x0) + assert sol2.rotors[0].extra.dp_NL == sol3.rotors[0].extra.dp_NL + assert sol2.rotors[0].extra.x0 == sol3.rotors[0].extra.x0 + +def test_TI_rotor_differences(): + wf_curled_TI, layout = get_curled_windfarm(couple_x0 = False, TIamb = 0.1) + wf_curled_TI_couple, _ = get_curled_windfarm(couple_x0 = True, TIamb = 0.1) + wf = get_gaussian_windfarm() + yaws, tilts = get_yaws_tilts(20) + ctprime = 1.33 + for yaw, tilt in zip(yaws, tilts): + setpoints = [(ctprime, yaw, tilt)] + sol1 = wf_curled_TI(layout, setpoints) + sol2 = wf_curled_TI_couple(layout, setpoints) + sol3 = wf(layout, setpoints) + # ensure that with TI, the new UMM models (with TI adjustments) are different + assert sol1.rotors[0].extra.dp_NL != sol3.rotors[0].extra.dp_NL + assert sol2.rotors[0].extra.dp_NL != sol3.rotors[0].extra.dp_NL + assert sol2.rotors[0].u4 != sol3.rotors[0].u4 + +test_wake_shape_rotation() +test_TI_rotor_equivalence() +test_TI_rotor_differences() + \ No newline at end of file diff --git a/tests/test_wake.py b/tests/test_wake.py index bef7e83..eec14c3 100644 --- a/tests/test_wake.py +++ b/tests/test_wake.py @@ -2,6 +2,7 @@ import numpy as np from mitwindfarm import RotorSolution, GaussianWakeModel +# helper functions to test tilt @fixture def grid_info(): xturb = 1 @@ -21,7 +22,7 @@ def wake_model_args(): an, u4, REWS = 0.3, 0.5, 1.0 return yaw, tilt, Cp, Ct, Ctprime, an, u4, REWS - +# test that wake follows centerline as provided by v4 and w4 @mark.parametrize('yturb, zturb, v4, w4', [(1, 1, 0, 0), (1, 0, 0.5, 0.0), (0, 1, -0.5, 0.0), (-1, 1, 0, 0.5), (1, -1, 0, -0.5), (-1, -1, 0.5, 0.5), (0, 0, -0.5, 0.5)]) def test_v4_w4_centerline_wake(grid_info, wake_model, wake_model_args, yturb, zturb, v4, w4): # get data from fixtures