diff --git a/examples/Quick_Starts/Automated_Meshing/README.md b/examples/Quick_Starts/Automated_Meshing/README.md new file mode 100644 index 0000000..3207f91 --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/README.md @@ -0,0 +1,13 @@ +The following example demonstrates the use of automated meshing using the ONERA M6 wing. + +To run the demo case follow these steps: + +1. Run 'python3 submit_cases.py` -> this script will upload the geometry file to the Flexcompute servers, generate the surface and volume mesh and then submit the CFD case. + +2. Run `python download_data.py` -> this script will download the csv files containing the loads and residual histories. + +3. Run `python convergence_plots.py` -> this script will plot the load and residual convergence histories. + +4. Run `python download_plot_sectional_forces.py` -> this script will download and plot the sectional loads. + +5. Run `download_vis_figures.py` -> this script will download Cp, Cf and streamline visualizations to the folder vis_figures. diff --git a/examples/Quick_Starts/Automated_Meshing/convergence_plots.py b/examples/Quick_Starts/Automated_Meshing/convergence_plots.py new file mode 100644 index 0000000..0bf098a --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/convergence_plots.py @@ -0,0 +1,82 @@ +"""Plot the loads and residuals convergence plots for ONERA M6 automeshing quick-start""" + +import os + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["CL", "CD"] +residuals = ["0_cont", "1_momx", "2_momy", "3_momz", "4_energ", "5_nuHat"] +figures = [] +axes = [] + + +def plot_loads(data, plot_name): + """Plot the loads""" + x = data["pseudo_step"] + for ax, load in zip(axes, loads): + ax.plot(x, data[load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Pseudo step") + ax.grid(which="major", color="gray") + if load == "CL": + ax.set_ylim(0.27, 0.28) + elif load == "CD": + ax.set_ylim(0.017, 0.018) + + +def plot_residuals(data, plot_name): + """Plot the residuals""" + x = data["pseudo_step"] + for ax, res in zip(axes, residuals): + for res in residuals: + ax.semilogy(x, data[res], label=plot_name + " " + res) + ax.set_ylabel("Residuals") + ax.legend(fontsize="8") + ax.set_title("ONERAM6 - Automated Meshing Quick-Start") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -2)) + ax.set_ylim([1e-7, 1e-2]) + ax.set_xlim([0, 5000]) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +# calculate and plot loads convergence histories +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "total_forces_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_loads(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) + +for ax in axes: + ax.cla() + + +# plot residual convergence histories +fig, ax = plt.subplots(figsize=(8, 6)) +figures.append(fig) +axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), case_name, "nonlinear_residual_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_residuals(data, case_name) + +figures[0].savefig(os.path.join(dir_path, "Residuals.png"), dpi=500) diff --git a/examples/Quick_Starts/Automated_Meshing/download_data.py b/examples/Quick_Starts/Automated_Meshing/download_data.py new file mode 100644 index 0000000..bb46afc --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/download_data.py @@ -0,0 +1,29 @@ +"""Download the results for the ONERA M6 automeshing quick-start""" + +import os + +from flow360 import MyCases + +# read in case_name_list +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +my_cases = MyCases(limit=None) + +case = None + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + # download the files + case.results.download( + nonlinear_residuals=True, + surface_forces=True, + total_forces=True, + destination=case_folder, + ) diff --git a/examples/Quick_Starts/Automated_Meshing/download_plot_sectional_forces.py b/examples/Quick_Starts/Automated_Meshing/download_plot_sectional_forces.py new file mode 100644 index 0000000..7c2641b --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/download_plot_sectional_forces.py @@ -0,0 +1,58 @@ +"""Plot the sectional loads for the ONERA M6 wing automeshing quick-start case""" + +import os + +import matplotlib.pyplot as plt +import pandas as pd +from flow360 import MyCases + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["wing_CFx_per_span", "wing_CFz_per_span"] +figures = [] +axes = [] + + +def plot_sectional_forces(data, plot_name): + """Plots the sectional loads""" + for ax, load in zip(axes, loads): + ax.plot(data["Y"], data["fluid/" + load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Y") + ax.grid(which="major", color="gray") + + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == case_name: + break + print(case.name) + forces = "results/postprocess/forceDistribution.csv" + # print(case.results) + case._download_file(forces, to_folder=case_folder) + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "forceDistribution.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_sectional_forces(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) diff --git a/examples/Quick_Starts/Automated_Meshing/download_vis_figures.py b/examples/Quick_Starts/Automated_Meshing/download_vis_figures.py new file mode 100644 index 0000000..b91ed37 --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/download_vis_figures.py @@ -0,0 +1,70 @@ +"""Downloads visualizations of surface CP, CF and streamlines""" + +import os + +from flow360 import MyCases +from PIL import Image + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +fields = ["Cp", "Cf", "Fv"] + + +def fetch_png(case, field, res="H"): + """Download the required figures from Flexcompute servers""" + # download the legend i.e. color bar + case_name = case.name + os.makedirs("visualize", exist_ok=True) + + legend = f"visualize/{field}Legend.png" + case._download_file(legend, to_file=legend) + + # list all available theta and phi + view_angles = [(0, 0), (180, 0)] + for theta in [60, 120]: + for phi in range(0, 360, 90): + view_angles.append((theta, phi)) + # download the contour + axis files + for theta, phi in view_angles: + fname = f"{theta:03d}_{phi:03d}.png" + contour = f"visualize/{field}_{res}_{fname}" + axis = f"visualize/Ax_{fname}" + case._download_file(contour, to_file=contour) + case._download_file(axis, to_file=axis) + # load and overlap contour + axis + legend + img_contour = Image.open(contour).convert("RGBA") + img_axis = Image.open(axis) + img_axis = img_axis.resize((img_axis.width * 3, img_axis.height * 3)) + img_axis = img_axis.convert("RGBA") + img_legend = Image.open(legend).convert("RGBA") + background = Image.new("RGBA", img_contour.size, (67, 100, 200)) + img_contour.paste(img_axis, (0, img_contour.height - img_axis.height), img_axis) + img_contour.paste( + img_legend, + (-int(0.1 * img_contour.height), int(0.1 * img_contour.height)), + img_legend, + ) + background.paste(img_contour, (0, 0), img_contour) + background.save( + f"vis_figures/{case_name}_{field}_{res}_{theta:03d}_{phi:03d}_final.png" + ) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "vis_figures") +os.makedirs(dir_path, exist_ok=True) + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + for field in fields: + fetch_png(case, field) diff --git a/examples/Quick_Starts/Automated_Meshing/om6Case.json b/examples/Quick_Starts/Automated_Meshing/om6Case.json new file mode 100644 index 0000000..2028d61 --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/om6Case.json @@ -0,0 +1,54 @@ +{ + "geometry" : { + "refArea" : 1.15315084119231, + "momentCenter" : [0.0, 0.0, 0.0], + "momentLength" : [1.47602, 0.801672958512342, 1.47602] + }, + "volumeOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Mach"] + }, + "surfaceOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Cp", "Cf"] + }, + "navierStokesSolver" : { + "absoluteTolerance" : 1e-10, + "kappaMUSCL" : -1.0 + }, + "turbulenceModelSolver" : { + "modelType" : "SpalartAllmaras", + "absoluteTolerance" : 1e-8 + }, + "freestream" : + { + "Reynolds" : 14.6e+6, + "Mach" : 0.84, + "Temperature" : 297.78, + "alphaAngle" : 3.06, + "betaAngle" : 0.0 + }, + "boundaries": { + "fluid/symmetric": { + "type": "SlipWall" + }, + "fluid/wing": { + "type": "NoSlipWall" + }, + "fluid/farfield": { + "type": "Freestream" + } + }, + "timeStepping" : { + "physicalSteps" : 1, + "timeStepSize" : "inf", + "maxPseudoSteps" : 5000, + "CFL" : { + "initial" : 1, + "final": 200, + "rampSteps" : 2250 + } + } +} diff --git a/examples/Quick_Starts/Automated_Meshing/om6SurfaceMesh.json b/examples/Quick_Starts/Automated_Meshing/om6SurfaceMesh.json new file mode 100644 index 0000000..fb14ade --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/om6SurfaceMesh.json @@ -0,0 +1,28 @@ +{ + "maxEdgeLength": 0.15, + "curvatureResolutionAngle": 10, + "growthRate": 1.07, + "edges": { + "wingLeadingEdge": { + "type": "aniso", + "method": "height", + "value": 3e-4 + }, + "wingTrailingEdge": { + "type": "aniso", + "method": "height", + "value": 3e-4 + }, + "rootAirfoilEdge": { + "type": "projectAnisoSpacing" + }, + "tipAirfoilEdge": { + "type": "projectAnisoSpacing" + } + }, + "faces": { + "wing": { + "maxEdgeLength": 0.15 + } + } +} diff --git a/examples/Quick_Starts/Automated_Meshing/om6VolumeMesh.json b/examples/Quick_Starts/Automated_Meshing/om6VolumeMesh.json new file mode 100644 index 0000000..dbf33a1 --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/om6VolumeMesh.json @@ -0,0 +1,49 @@ +{ + "refinementFactor": 1.45, + "refinement": [ + { + "type": "cylinder", + "radius": 1.1, + "length": 2.0, + "spacing": 0.075, + "axis": [0,1,0], + "center": [0.7,-1.0,0] + }, + { + "type": "cylinder", + "radius": 2.2, + "length": 2.0, + "spacing": 0.1, + "axis": [0,1,0], + "center": [0.7,-1.0,0] + }, + { + "type": "cylinder", + "radius": 3.3, + "length": 2.0, + "spacing": 0.175, + "axis": [0,1,0], + "center": [0.7,-1.0,0] + }, + { + "type": "cylinder", + "radius": 4.5, + "length": 2.0, + "spacing": 0.225, + "axis": [0,1,0], + "center": [0.7,-1.0,0] + }, + { + "type": "cylinder", + "radius": 6.5, + "length": 14.5, + "spacing": 0.3, + "axis": [-1,0,0], + "center": [2,-1.0,0] + } + ], + "volume": { + "firstLayerThickness": 1.35e-06, + "growthRate": 1.04 + } +} diff --git a/examples/Quick_Starts/Automated_Meshing/om6wing.csm b/examples/Quick_Starts/Automated_Meshing/om6wing.csm new file mode 100644 index 0000000..d1ad7a4 --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/om6wing.csm @@ -0,0 +1,454 @@ +# OM6 WING TUTORIAL STEP 1 | 3D Sketches of Airfoils +#============================================================================================ +mark +skbeg 0.805900000 0.000000000 0.0000000000 +spline 0.804129438 0.000231777 0.0000000000 +spline 0.802038127 0.00050538 0.0000000000 +spline 0.799568688 0.000828465 0.0000000000 +spline 0.796652459 0.001209978 0.0000000000 +spline 0.79320772 0.001660638 0.0000000000 +spline 0.789138892 0.002192934 0.0000000000 +spline 0.784330973 0.002821859 0.0000000000 +spline 0.778649297 0.003565302 0.0000000000 +spline 0.771932201 0.004444055 0.0000000000 +spline 0.763988848 0.005483182 0.0000000000 +spline 0.754592054 0.006710326 0.0000000000 +spline 0.743469828 0.008150711 0.0000000000 +spline 0.730298924 0.009828112 0.0000000000 +spline 0.714691059 0.01168966 0.0000000000 +spline 0.696181873 0.01377404 0.0000000000 +spline 0.677546241 0.015782584 0.0000000000 +spline 0.658809389 0.017717067 0.0000000000 +spline 0.639969622 0.019585546 0.0000000000 +spline 0.621026379 0.021397048 0.0000000000 +spline 0.601979738 0.023158745 0.0000000000 +spline 0.582826477 0.024875071 0.0000000000 +spline 0.563568046 0.026546507 0.0000000000 +spline 0.544202188 0.02816959 0.0000000000 +spline 0.524728985 0.029736904 0.0000000000 +spline 0.505146501 0.031237732 0.0000000000 +spline 0.485454577 0.032658372 0.0000000000 +spline 0.465652485 0.033983514 0.0000000000 +spline 0.445738213 0.035196957 0.0000000000 +spline 0.425710711 0.036282343 0.0000000000 +spline 0.405570303 0.037224763 0.0000000000 +spline 0.385316666 0.03801116 0.0000000000 +spline 0.36494706 0.038630897 0.0000000000 +spline 0.344459632 0.039072691 0.0000000000 +spline 0.323856315 0.039344199 0.0000000000 +spline 0.303134933 0.039432365 0.0000000000 +spline 0.28229307 0.039342668 0.0000000000 +spline 0.261331288 0.039078252 0.0000000000 +spline 0.240247897 0.038642421 0.0000000000 +spline 0.219041847 0.038037432 0.0000000000 +spline 0.197712253 0.037261431 0.0000000000 +spline 0.176258067 0.036306359 0.0000000000 +spline 0.154678563 0.035154486 0.0000000000 +spline 0.132971566 0.033774383 0.0000000000 +spline 0.111130628 0.032116888 0.0000000000 +spline 0.09266206 0.030456815 0.0000000000 +spline 0.077072569 0.028830428 0.0000000000 +spline 0.063937366 0.027269399 0.0000000000 +spline 0.052891459 0.025799921 0.0000000000 +spline 0.043619176 0.024441174 0.0000000000 +spline 0.035850623 0.023202828 0.0000000000 +spline 0.029355794 0.022026617 0.0000000000 +spline 0.023935875 0.020811965 0.0000000000 +spline 0.01942759 0.019503102 0.0000000000 +spline 0.015683539 0.018096082 0.0000000000 +spline 0.012585821 0.01661927 0.0000000000 +spline 0.010031763 0.015113607 0.0000000000 +spline 0.007931104 0.013618421 0.0000000000 +spline 0.006214456 0.012165141 0.0000000000 +spline 0.004815333 0.010775528 0.0000000000 +spline 0.003683285 0.009462797 0.0000000000 +spline 0.002774553 0.008233316 0.0000000000 +spline 0.00205029 0.007088535 0.0000000000 +spline 0.001479955 0.006026843 0.0000000000 +spline 0.001037032 0.005044773 0.0000000000 +spline 0.000697668 0.004137732 0.0000000000 +spline 0.00044389 0.003300886 0.0000000000 +spline 0.000260467 0.002529075 0.0000000000 +spline 0.000134988 0.001817627 0.0000000000 +spline 5.60906E-05 0.001161785 0.0000000000 +spline 1.32974E-05 0.000557199 0.0000000000 +spline 0.000000000 0.000000000 0.0000000000 +skend +skbeg 0.000000000 0.000000000 0.000000000 +spline 1.32974E-05 -0.000557199 0.000000000 +spline 5.60906E-05 -0.001161785 0.000000000 +spline 0.000134988 -0.001817627 0.000000000 +spline 0.000260467 -0.002529075 0.000000000 +spline 0.00044389 -0.003300886 0.000000000 +spline 0.000697668 -0.004137732 0.000000000 +spline 0.001037032 -0.005044773 0.000000000 +spline 0.001479955 -0.006026843 0.000000000 +spline 0.00205029 -0.007088535 0.000000000 +spline 0.002774553 -0.008233316 0.000000000 +spline 0.003683285 -0.009462797 0.000000000 +spline 0.004815333 -0.010775528 0.000000000 +spline 0.006214456 -0.012165141 0.000000000 +spline 0.007931104 -0.013618421 0.000000000 +spline 0.010031763 -0.015113607 0.000000000 +spline 0.012585821 -0.01661927 0.000000000 +spline 0.015683539 -0.018096082 0.000000000 +spline 0.01942759 -0.019503102 0.000000000 +spline 0.023935875 -0.020811965 0.000000000 +spline 0.029355794 -0.022026617 0.000000000 +spline 0.035850623 -0.023202828 0.000000000 +spline 0.043619176 -0.024441174 0.000000000 +spline 0.052891459 -0.025799921 0.000000000 +spline 0.063937366 -0.027269399 0.000000000 +spline 0.077072569 -0.028830428 0.000000000 +spline 0.09266206 -0.030456815 0.000000000 +spline 0.111130628 -0.032116888 0.000000000 +spline 0.132971566 -0.033774383 0.000000000 +spline 0.154678563 -0.035154486 0.000000000 +spline 0.176258067 -0.036306359 0.000000000 +spline 0.197712253 -0.037261431 0.000000000 +spline 0.219041847 -0.038037432 0.000000000 +spline 0.240247897 -0.038642421 0.000000000 +spline 0.261331288 -0.039078252 0.000000000 +spline 0.28229307 -0.039342668 0.000000000 +spline 0.303134933 -0.039432365 0.000000000 +spline 0.323856315 -0.039344199 0.000000000 +spline 0.344459632 -0.039072691 0.000000000 +spline 0.36494706 -0.038630897 0.000000000 +spline 0.385316666 -0.03801116 0.000000000 +spline 0.405570303 -0.037224763 0.000000000 +spline 0.425710711 -0.036282343 0.000000000 +spline 0.445738213 -0.035196957 0.000000000 +spline 0.465652485 -0.033983514 0.000000000 +spline 0.485454577 -0.032658372 0.000000000 +spline 0.505146501 -0.031237732 0.000000000 +spline 0.524728985 -0.029736904 0.000000000 +spline 0.544202188 -0.02816959 0.000000000 +spline 0.563568046 -0.026546507 0.000000000 +spline 0.582826477 -0.024875071 0.000000000 +spline 0.601979738 -0.023158745 0.000000000 +spline 0.621026379 -0.021397048 0.000000000 +spline 0.639969622 -0.019585546 0.000000000 +spline 0.658809389 -0.017717067 0.000000000 +spline 0.677546241 -0.015782584 0.000000000 +spline 0.696181873 -0.01377404 0.000000000 +spline 0.714691059 -0.01168966 0.000000000 +spline 0.730298924 -0.009828112 0.000000000 +spline 0.743469828 -0.008150711 0.000000000 +spline 0.754592054 -0.006710326 0.000000000 +spline 0.763988848 -0.005483182 0.000000000 +spline 0.771932201 -0.004444055 0.000000000 +spline 0.778649297 -0.003565302 0.000000000 +spline 0.784330973 -0.002821859 0.000000000 +spline 0.789138892 -0.002192934 0.000000000 +spline 0.79320772 -0.001660638 0.000000000 +spline 0.796652459 -0.001209978 0.000000000 +spline 0.799568688 -0.000828465 0.000000000 +spline 0.802038127 -0.00050538 0.000000000 +spline 0.804129438 -0.000231777 0.000000000 +skend +group +store rootAirfoil + +mark +skbeg 0.45333164 0.000000000 0.000000000 +spline 0.45233567 0.000130378 0.000000000 +spline 0.451159275 0.000284284 0.000000000 +spline 0.449770176 0.000466025 0.000000000 +spline 0.44812975 0.000680632 0.000000000 +spline 0.446192029 0.000934135 0.000000000 +spline 0.443903249 0.001233561 0.000000000 +spline 0.441198717 0.001587341 0.000000000 +spline 0.438002684 0.002005539 0.000000000 +spline 0.43422421 0.002499852 0.000000000 +spline 0.429755947 0.003084378 0.000000000 +spline 0.4244701 0.003774666 0.000000000 +spline 0.41821367 0.004584906 0.000000000 +spline 0.410804826 0.00552847 0.000000000 +spline 0.402025152 0.006575621 0.000000000 +spline 0.391613439 0.007748118 0.000000000 +spline 0.381130598 0.008877956 0.000000000 +spline 0.370590818 0.009966133 0.000000000 +spline 0.359993149 0.011017183 0.000000000 +spline 0.349337271 0.012036182 0.000000000 +spline 0.338623231 0.013027165 0.000000000 +spline 0.327849215 0.013992625 0.000000000 +spline 0.31701604 0.014932835 0.000000000 +spline 0.306122435 0.015845845 0.000000000 +spline 0.295168447 0.016727484 0.000000000 +spline 0.284152987 0.017571724 0.000000000 +spline 0.273075964 0.018370857 0.000000000 +spline 0.261936971 0.01911627 0.000000000 +spline 0.250734874 0.019798851 0.000000000 +spline 0.239469084 0.020409398 0.000000000 +spline 0.228139782 0.020939524 0.000000000 +spline 0.216746788 0.021381885 0.000000000 +spline 0.205288559 0.021730497 0.000000000 +spline 0.193764052 0.021979014 0.000000000 +spline 0.182174357 0.022131741 0.000000000 +spline 0.170518248 0.022181336 0.000000000 +spline 0.158794367 0.02213088 0.000000000 +spline 0.14700303 0.021982142 0.000000000 +spline 0.135143285 0.02173698 0.000000000 +spline 0.123214542 0.021396664 0.000000000 +spline 0.111216305 0.020960151 0.000000000 +spline 0.099147982 0.020422908 0.000000000 +spline 0.087009166 0.019774961 0.000000000 +spline 0.074798633 0.01899863 0.000000000 +spline 0.062512756 0.018066263 0.000000000 +spline 0.052123891 0.017132445 0.000000000 +spline 0.043354553 0.016217577 0.000000000 +spline 0.035965791 0.015339473 0.000000000 +spline 0.029752292 0.014512868 0.000000000 +spline 0.024536484 0.013748551 0.000000000 +spline 0.020166549 0.013051962 0.000000000 +spline 0.016513104 0.012390324 0.000000000 +spline 0.013464312 0.011707063 0.000000000 +spline 0.01092833 0.010970807 0.000000000 +spline 0.008822242 0.010179335 0.000000000 +spline 0.007079726 0.009348605 0.000000000 +spline 0.005643027 0.008501646 0.000000000 +spline 0.004461373 0.007660579 0.000000000 +spline 0.003495731 0.006843086 0.000000000 +spline 0.002708702 0.006061407 0.000000000 +spline 0.002071907 0.005322975 0.000000000 +spline 0.00156073 0.004631372 0.000000000 +spline 0.001153321 0.003987414 0.000000000 +spline 0.000832498 0.003390195 0.000000000 +spline 0.000583347 0.002837765 0.000000000 +spline 0.000392449 0.002327541 0.000000000 +spline 0.000249695 0.001856801 0.000000000 +spline 0.000146517 0.001422645 0.000000000 +spline 7.5933E-05 0.001022444 0.000000000 +spline 3.15519E-05 0.000653523 0.000000000 +spline 7.47997E-06 0.000313433 0.000000000 +spline 0.000000000 0.000000000 0.000000000 +skend +skbeg 0.00000000 0.000000000 0.000000000 +spline 7.47997E-06 -0.000313433 0.000000000 +spline 3.15519E-05 -0.000653523 0.000000000 +spline 7.5933E-05 -0.001022444 0.000000000 +spline 0.000146517 -0.001422645 0.000000000 +spline 0.000249695 -0.001856801 0.000000000 +spline 0.000392449 -0.002327541 0.000000000 +spline 0.000583347 -0.002837765 0.000000000 +spline 0.000832498 -0.003390195 0.000000000 +spline 0.001153321 -0.003987414 0.000000000 +spline 0.00156073 -0.004631372 0.000000000 +spline 0.002071907 -0.005322975 0.000000000 +spline 0.002708702 -0.006061407 0.000000000 +spline 0.003495731 -0.006843086 0.000000000 +spline 0.004461373 -0.007660579 0.000000000 +spline 0.005643027 -0.008501646 0.000000000 +spline 0.007079726 -0.009348605 0.000000000 +spline 0.008822242 -0.010179335 0.000000000 +spline 0.01092833 -0.010970807 0.000000000 +spline 0.013464312 -0.011707063 0.000000000 +spline 0.016513104 -0.012390324 0.000000000 +spline 0.020166549 -0.013051962 0.000000000 +spline 0.024536484 -0.013748551 0.000000000 +spline 0.029752292 -0.014512868 0.000000000 +spline 0.035965791 -0.015339473 0.000000000 +spline 0.043354553 -0.016217577 0.000000000 +spline 0.052123891 -0.017132445 0.000000000 +spline 0.062512756 -0.018066263 0.000000000 +spline 0.074798633 -0.01899863 0.000000000 +spline 0.087009166 -0.019774961 0.000000000 +spline 0.099147982 -0.020422908 0.000000000 +spline 0.111216305 -0.020960151 0.000000000 +spline 0.123214542 -0.021396664 0.000000000 +spline 0.135143285 -0.02173698 0.000000000 +spline 0.14700303 -0.021982142 0.000000000 +spline 0.158794367 -0.02213088 0.000000000 +spline 0.170518248 -0.022181336 0.000000000 +spline 0.182174357 -0.022131741 0.000000000 +spline 0.193764052 -0.021979014 0.000000000 +spline 0.205288559 -0.021730497 0.000000000 +spline 0.216746788 -0.021381885 0.000000000 +spline 0.228139782 -0.020939524 0.000000000 +spline 0.239469084 -0.020409398 0.000000000 +spline 0.250734874 -0.019798851 0.000000000 +spline 0.261936971 -0.01911627 0.000000000 +spline 0.273075964 -0.018370857 0.000000000 +spline 0.284152987 -0.017571724 0.000000000 +spline 0.295168447 -0.016727484 0.000000000 +spline 0.306122435 -0.015845845 0.000000000 +spline 0.31701604 -0.014932835 0.000000000 +spline 0.327849215 -0.013992625 0.000000000 +spline 0.338623231 -0.013027165 0.000000000 +spline 0.349337271 -0.012036182 0.000000000 +spline 0.359993149 -0.011017183 0.000000000 +spline 0.370590818 -0.009966133 0.000000000 +spline 0.381130598 -0.008877956 0.000000000 +spline 0.391613439 -0.007748118 0.000000000 +spline 0.402025152 -0.006575621 0.000000000 +spline 0.410804826 -0.00552847 0.000000000 +spline 0.41821367 -0.004584906 0.000000000 +spline 0.4244701 -0.003774666 0.000000000 +spline 0.429755947 -0.003084378 0.000000000 +spline 0.43422421 -0.002499852 0.000000000 +spline 0.438002684 -0.002005539 0.000000000 +spline 0.441198717 -0.001587341 0.000000000 +spline 0.443903249 -0.001233561 0.000000000 +spline 0.446192029 -0.000934135 0.000000000 +spline 0.44812975 -0.000680632 0.000000000 +spline 0.449770176 -0.000466025 0.000000000 +spline 0.451159275 -0.000284284 0.000000000 +spline 0.45233567 -0.000130378 0.000000000 +skend +group +store tipAirfoil + +# OM6 WING TUTORIAL STEP 2 | Wing Planform +#============================================================================================ + +# SWEPT WING OM6 PARAMETERS +#-------------------------------------------------------------------------------------------- +DESPMTR span 1.1963 +CONPMTR LEsweep 30 + +# TIP FACE +#-------------------------------------------------------------------------------------------- +restore tipAirfoil +join +rotatex 90 0 0 +translate span/tand(90-LEsweep) -span 0 + +# COLLECTING NODE COORDINATES AT TIP FACE TO ADD ATTRIBUTE AFTER BLEND +#-------------------------------------------------------------------------------------------- +dimension tipLeadingPoint 1 3 +dimension tipTrailingPointUp 1 3 +dimension tipTrailingPointLow 1 3 + +set xmin @xmax +set zmin @zmax +set zmax @zmin + +set numNodes @nnode +patbeg inode numNodes + evaluate node @ibody inode + IFTHEN @edata[1] LT xmin + set xmin @edata[1] + set tipLeadingPoint "xmin;@edata[2];@edata[3];" + set leadingNodeID inode + ENDIF +patend + +patbeg inode numNodes + IFTHEN inode NE leadingNodeID + evaluate node @ibody inode + IFTHEN @edata[3] GT zmax + set zmax @edata[3] + set tipTrailingPointUp "@edata[1];@edata[2];zmax;" + ENDIF + + IFTHEN @edata[3] LT zmin + set zmin @edata[3] + set tipTrailingPointLow "@edata[1];@edata[2];zmin;" + ENDIF + ENDIF +patend + +# TIP AIRFOIL --> TIP FACE +combine +store tipFace + +# ROOT FACE +#-------------------------------------------------------------------------------------------- +restore rootAirfoil +join +rotatex 90 0 0 + +# COLLECTING NODE COORDINATES AT ROOT FACE TO ADD ATTRIBUTE AFTER BLEND +#-------------------------------------------------------------------------------------------- +# defining arrays with one row and three columns +dimension rootLeadingPoint 1 3 +dimension rootTrailingPointUp 1 3 +dimension rootTrailingPointLow 1 3 + +# initializing xmin, zmin, zmax with their opposite extremes +set xmin @xmax +set zmin @zmax +set zmax @zmin + +set numNodes @nnode +patbeg inode numNodes + evaluate node @ibody inode + IFTHEN @edata[1] LT xmin + set xmin @edata[1] + set rootLeadingPoint "xmin;@edata[2];@edata[3];" + set leadingNodeID inode + ENDIF +patend + +patbeg inode numNodes + IFTHEN inode NE leadingNodeID + evaluate node @ibody inode + IFTHEN @edata[3] GT zmax + set zmax @edata[3] + set rootTrailingPointUp "@edata[1];@edata[2];zmax;" + ENDIF + + IFTHEN @edata[3] LT zmin + set zmin @edata[3] + set rootTrailingPointLow "@edata[1];@edata[2];zmin;" + ENDIF + ENDIF +patend + +# ROOT AIRFOIL --> ROOT FACE +combine +store rootFace + +# OM6 WING TUTORIAL STEP 3 | Wing Solid Model +#============================================================================================ +mark +restore tipFace +restore rootFace +blend "-1;1.1" + +# OM6 WING TUTORIAL STEP 4 | Adding Attributes | Method 1: Using Edge Attribute UDPRIM +#============================================================================================= + +#ADDING EDGE ATTRIBUTES +#-------------------------------------------------------------------------------------------- + +# METHOD 1: USING COORDINATES OF NODES +udparg edgeAttr attrname $edgeName attrstr $wingLeadingEdge +udprim edgeAttr xyzs "rootLeadingPoint[1];rootLeadingPoint[2];rootLeadingPoint[3];tipLeadingPoint[1];tipLeadingPoint[2];tipLeadingPoint[3];" +udparg edgeAttr attrname $edgeName attrstr $wingTrailingEdge +udprim edgeAttr xyzs "rootTrailingPointUp[1];rootTrailingPointUp[2];rootTrailingPointUp[3];tipTrailingPointUp[1];tipTrailingPointUp[2];tipTrailingPointUp[3];" +udparg edgeAttr attrname $edgeName attrstr $wingTrailingEdge +udprim edgeAttr xyzs "rootTrailingPointLow[1];rootTrailingPointLow[2];rootTrailingPointLow[3];tipTrailingPointLow[1];tipTrailingPointLow[2];tipTrailingPointLow[3];" + + +# OM6 WING TUTORIAL STEP 4 | Adding Attributes | Method 2: Using Bounding Box +#============================================================================================= + +# METHOD 2: USING BOUNDING BOX +select edge @xmin @xmax -0.01 0.01 @zmin @zmax +attribute edgeName $rootAirfoilEdge + +# OM6 WING TUTORIAL STEP 4 | Adding Attributes | Method 3: Using Bounding Box +#============================================================================================= + +# METHOD 3: USING EDGE ID +select edge 2 +attribute edgeName $tipAirfoilEdge + +select edge 5 +attribute edgeName $tipAirfoilEdge + + +# OM6 WING TUTORIAL STEP 5 | Adding Face and Group Attributes +#============================================================================================= + +store wingModel + +#ADDING FACE AND GROUP ATTRIBUTE +#-------------------------------------------------------------------------------------------- +restore wingModel +attribute faceName $wing +attribute groupName $wing +scale 1/0.8059 0 0 0 + +END diff --git a/examples/Quick_Starts/Automated_Meshing/submit_case.py b/examples/Quick_Starts/Automated_Meshing/submit_case.py new file mode 100644 index 0000000..001c32c --- /dev/null +++ b/examples/Quick_Starts/Automated_Meshing/submit_case.py @@ -0,0 +1,33 @@ +"""Submit surface mesh from geometry file, volume mesh from surface mesh and case from volume mesh""" + +import flow360 as fl + +case_name_list = [] + +# submit surface mesh +params = fl.SurfaceMeshingParams("om6SurfaceMesh.json") +surface_mesh = fl.SurfaceMesh.create( + "om6wing.csm", params=params, name="ONERAM6_Automated_Meshing_Surface" +) +surface_mesh = surface_mesh.submit() + +# submit volume mesh +params = fl.VolumeMeshingParams("om6VolumeMesh.json") +volume_mesh = surface_mesh.create_volume_mesh( + "ONERAM6_Automated_Meshing_Volume", params=params +) +volume_mesh = volume_mesh.submit() + + +params = fl.Flow360Params("om6Case.json") + +# submit case +case = fl.Case.create("ONERAM6_Automated_Meshing", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/ONERAM6/Flow360.json b/examples/Quick_Starts/ONERAM6/Flow360.json new file mode 100644 index 0000000..04b1b2d --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/Flow360.json @@ -0,0 +1,55 @@ +{ + "geometry" : { + "refArea" : 1.15315084119231, + "momentCenter" : [0.0, 0.0, 0.0], + "momentLength" : [1.47602, 0.801672958512342, 1.47602] + }, + "volumeOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Mach"] + }, + "surfaceOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Cp", "Cf"] + }, + "navierStokesSolver" : { + "absoluteTolerance" : 1e-10, + "kappaMUSCL" : -1.0 + }, + "turbulenceModelSolver" : { + "modelType" : "SpalartAllmaras", + "absoluteTolerance" : 1e-8 + }, + "freestream" : + { + "Reynolds" : 14.6e6, + "Mach" : 0.84, + "Temperature" : 288.15, + "alphaAngle" : 3.06, + "betaAngle" : 0.0 + }, + "boundaries" : { + "1" : { + "type" : "NoSlipWall", + "name" : "wing" + }, + "2" : { + "type" : "SlipWall", + "name" : "symmetry" + }, + "3" : { + "type" : "Freestream", + "name" : "freestream" + } + }, + "timeStepping" : { + "maxPseudoSteps" : 500, + "CFL" : { + "initial" : 5, + "final": 200, + "rampSteps" : 40 + } + } +} diff --git a/examples/Quick_Starts/ONERAM6/README.md b/examples/Quick_Starts/ONERAM6/README.md new file mode 100644 index 0000000..02ec3b8 --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/README.md @@ -0,0 +1,16 @@ +The following example, launches the OM6 Quick-start case. + +To run the demo case follow these steps: + +1. Run `python submit_cases_from_downloads.py` -> this script will download the ONERAM6 mesh, and upload it to the Flexcompute servers. The case will also be submitted. Alternatively the script `submit_cases_from_id.py` can also be used to run the case from a mesh already uploaded to Flexcompute servers. + +2. Run `python download_data.py` -> this script will download the csv files containing the loads and residual histories. + +3. Run `python convergence_plots.py` -> this script will plot the load and residual convergence histories. + +4. Run `python download_plot_sectional_forces.py` -> this script will download and plot the sectional loads. + +5. Run `download_vis_figures.py` -> this script will download Cp, Cf and streamline visualizations to the vis_figures folder. + + + diff --git a/examples/Quick_Starts/ONERAM6/convergence_plots.py b/examples/Quick_Starts/ONERAM6/convergence_plots.py new file mode 100644 index 0000000..3f1abfc --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/convergence_plots.py @@ -0,0 +1,82 @@ +"""Plot the loads and residuals convergence plots for ONERA M6 quick-start""" + +import os + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["CL", "CD"] +residuals = ["0_cont", "1_momx", "2_momy", "3_momz", "4_energ", "5_nuHat"] +figures = [] +axes = [] + + +def plot_loads(data, plot_name): + """Plot the loads""" + x = data["pseudo_step"] + for ax, load in zip(axes, loads): + ax.plot(x, data[load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Pseudo step") + ax.grid(which="major", color="gray") + if load == "CL": + ax.set_ylim(0.255, 0.265) + elif load == "CD": + ax.set_ylim(0.0203, 0.0212) + + +def plot_residuals(data, plot_name): + """Plot the residuals""" + x = data["pseudo_step"] + for ax, res in zip(axes, residuals): + for res in residuals: + ax.semilogy(x, data[res], label=plot_name + " " + res) + ax.set_ylabel("Residuals") + ax.legend(fontsize="8") + ax.set_title("ONERAM6 - Quick-Start") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -2)) + ax.set_ylim([1e-9, 1e-2]) + ax.set_xlim([0, 500]) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +# calculate and plot loads convergence histories +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "total_forces_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_loads(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) + +for ax in axes: + ax.cla() + + +# plot residual convergence histories +fig, ax = plt.subplots(figsize=(8, 6)) +figures.append(fig) +axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), case_name, "nonlinear_residual_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_residuals(data, case_name) + +figures[0].savefig(os.path.join(dir_path, "Residuals.png"), dpi=500) diff --git a/examples/Quick_Starts/ONERAM6/download_data.py b/examples/Quick_Starts/ONERAM6/download_data.py new file mode 100644 index 0000000..867c03d --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/download_data.py @@ -0,0 +1,29 @@ +"""Download the results for the ONERA M6 Quick start case""" + +import os + +from flow360 import MyCases + +# read in case_name_list +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +my_cases = MyCases(limit=None) + +case = None + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + # download the files + case.results.download( + nonlinear_residuals=True, + surface_forces=True, + total_forces=True, + destination=case_folder, + ) diff --git a/examples/Quick_Starts/ONERAM6/download_plot_sectional_forces.py b/examples/Quick_Starts/ONERAM6/download_plot_sectional_forces.py new file mode 100644 index 0000000..e3c72f7 --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/download_plot_sectional_forces.py @@ -0,0 +1,57 @@ +"""Plot the sectional loads for the ONERA M6 wing quick-start case""" + +import os + +import matplotlib.pyplot as plt +import pandas as pd +from flow360 import MyCases + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["wing_CFx_per_span", "wing_CFz_per_span"] +figures = [] +axes = [] + + +def plot_sectional_forces(data, plot_name): + """Plots the sectional loads""" + for ax, load in zip(axes, loads): + ax.plot(data["Y"], data[load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Y") + ax.grid(which="major", color="gray") + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == case_name: + break + print(case.name) + forces = "results/postprocess/forceDistribution.csv" + # print(case.results) + case._download_file(forces, to_folder=case_folder) + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "forceDistribution.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_sectional_forces(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) diff --git a/examples/Quick_Starts/ONERAM6/download_vis_figures.py b/examples/Quick_Starts/ONERAM6/download_vis_figures.py new file mode 100644 index 0000000..b91ed37 --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/download_vis_figures.py @@ -0,0 +1,70 @@ +"""Downloads visualizations of surface CP, CF and streamlines""" + +import os + +from flow360 import MyCases +from PIL import Image + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +fields = ["Cp", "Cf", "Fv"] + + +def fetch_png(case, field, res="H"): + """Download the required figures from Flexcompute servers""" + # download the legend i.e. color bar + case_name = case.name + os.makedirs("visualize", exist_ok=True) + + legend = f"visualize/{field}Legend.png" + case._download_file(legend, to_file=legend) + + # list all available theta and phi + view_angles = [(0, 0), (180, 0)] + for theta in [60, 120]: + for phi in range(0, 360, 90): + view_angles.append((theta, phi)) + # download the contour + axis files + for theta, phi in view_angles: + fname = f"{theta:03d}_{phi:03d}.png" + contour = f"visualize/{field}_{res}_{fname}" + axis = f"visualize/Ax_{fname}" + case._download_file(contour, to_file=contour) + case._download_file(axis, to_file=axis) + # load and overlap contour + axis + legend + img_contour = Image.open(contour).convert("RGBA") + img_axis = Image.open(axis) + img_axis = img_axis.resize((img_axis.width * 3, img_axis.height * 3)) + img_axis = img_axis.convert("RGBA") + img_legend = Image.open(legend).convert("RGBA") + background = Image.new("RGBA", img_contour.size, (67, 100, 200)) + img_contour.paste(img_axis, (0, img_contour.height - img_axis.height), img_axis) + img_contour.paste( + img_legend, + (-int(0.1 * img_contour.height), int(0.1 * img_contour.height)), + img_legend, + ) + background.paste(img_contour, (0, 0), img_contour) + background.save( + f"vis_figures/{case_name}_{field}_{res}_{theta:03d}_{phi:03d}_final.png" + ) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "vis_figures") +os.makedirs(dir_path, exist_ok=True) + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + for field in fields: + fetch_png(case, field) diff --git a/examples/Quick_Starts/ONERAM6/submit_case_from_download.py b/examples/Quick_Starts/ONERAM6/submit_case_from_download.py new file mode 100644 index 0000000..f66211c --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/submit_case_from_download.py @@ -0,0 +1,33 @@ +"""Case submission through mesh download and upload onto Flexcompute servers""" + +import os.path +from urllib.request import urlretrieve + +import flow360 as fl + +case_name_list = [] + +# download mesh to the current directory +URL = "https://simcloud-public-1.s3.amazonaws.com/om6/wing_tetra.1.lb8.ugrid" +MESH_FILENAME = "wing_tetra.1.lb8.ugrid" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + + +# submit mesh +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="ONERAM6_Mesh") +volume_mesh = volume_mesh.submit() + +params = fl.Flow360Params("Flow360.json") + +# submit case +case = fl.Case.create("ONERAM6_Quickstart", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/ONERAM6/submit_case_from_id.py b/examples/Quick_Starts/ONERAM6/submit_case_from_id.py new file mode 100644 index 0000000..b9dc79f --- /dev/null +++ b/examples/Quick_Starts/ONERAM6/submit_case_from_id.py @@ -0,0 +1,20 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID = "33f46ac0-e4e6-468e-be86-2289817b6472" + +params = fl.Flow360Params("Flow360.json") + +# submit case +case = fl.Case.create("ONERAM6_Quickstart", params, MESH_ID) +case_name_list.append(case.name) +case = case.submit() + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/S809/README.md b/examples/Quick_Starts/S809/README.md new file mode 100644 index 0000000..c4b70b2 --- /dev/null +++ b/examples/Quick_Starts/S809/README.md @@ -0,0 +1,9 @@ +The following example demonstrates the automated meshing workflow for the S809 airfoil and compares the results with the pre-meshed structured grid. + +To run the demo case follow these steps: + +1. Run `python submit_cases_from_downloads.py` -> this script will download the structured S809 mesh, and upload it to the Flexcompute servers. The cases will also be submitted for both automated mesh and structured mesh. Alternatively the script `submit_cases_from_id.py` can also be used to run the structured mesh case from a meshe already uploaded to Flexcompute servers. + +2. Run `python download_data.py` -> this script will download the csv files containing the loads and residual histories. + +3. Run `python convergence_plots.py` to cross-plot the loads and residual convergence histories for the automated mesh and structured mesh cases. diff --git a/examples/Quick_Starts/S809/convergence_plots.py b/examples/Quick_Starts/S809/convergence_plots.py new file mode 100644 index 0000000..5068a3e --- /dev/null +++ b/examples/Quick_Starts/S809/convergence_plots.py @@ -0,0 +1,87 @@ +"""Plot the loads and residuals convergence plots for automated meshing and structured grids S809 cases""" + +import os + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["CL", "CD"] +residuals = ["0_cont", "1_momx", "2_momy", "3_momz", "4_energ", "5_nuHat"] +figures = [] +axes = [] + + +def plot_loads(data, plot_name): + """Plot the loads""" + x = data["pseudo_step"] + for ax, load in zip(axes, loads): + ax.plot(x, data[load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Pseudo step") + ax.grid(which="major", color="gray") + if load == "CL": + ax.set_ylim(0.7, 0.8) + elif load == "CD": + ax.set_ylim(0.01, 0.016) + + +def plot_residuals(data, plot_name): + """Plot the residuals""" + x = data["pseudo_step"] + for ax, res in zip(axes, residuals): + for res in residuals: + if "Structured" in plot_name: + ax.semilogy(x, data[res], label=plot_name + " " + res) + else: + ax.semilogy(x, data[res], "--", label=plot_name + " " + res) + ax.set_ylabel("Residuals") + ax.legend(fontsize="8") + ax.set_title("S809") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -3)) + ax.set_ylim([1e-11, 1e-3]) + ax.set_xlim([0, 5000]) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +# calculate and plot loads convergence histories +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "total_forces_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_loads(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) + +for ax in axes: + ax.cla() + + +# plot residual convergence histories +fig, ax = plt.subplots(figsize=(8, 6)) +figures.append(fig) +axes.append(ax) + +for case_name in case_name_list: + if "Structured" in case_name: + figures[0].gca().set_prop_cycle(None) + csv_path = os.path.join(os.getcwd(), case_name, "nonlinear_residual_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_residuals(data, case_name) + +figures[0].savefig(os.path.join(dir_path, "Residuals.png"), dpi=500) diff --git a/examples/Quick_Starts/S809/download_data.py b/examples/Quick_Starts/S809/download_data.py new file mode 100644 index 0000000..83c3c19 --- /dev/null +++ b/examples/Quick_Starts/S809/download_data.py @@ -0,0 +1,29 @@ +"""Download the results for the S809 Quick start""" + +import os + +from flow360 import MyCases + +# read in case_name_list +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +my_cases = MyCases(limit=None) + +case = None + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + # download the files + case.results.download( + nonlinear_residuals=True, + surface_forces=True, + total_forces=True, + destination=case_folder, + ) diff --git a/examples/Quick_Starts/S809/s809.csm b/examples/Quick_Starts/S809/s809.csm new file mode 100644 index 0000000..0917b8e --- /dev/null +++ b/examples/Quick_Starts/S809/s809.csm @@ -0,0 +1,500 @@ +# s809 quasi model + +# MODEL PARAMETERS +#============================================================================================ +CFGPMTR span 0.01 + +#============================================================================================ +# START OF AIRFOIL COORDINATE DATA DEFINED AS SPLINE CONTROL POINTS +#============================================================================================ +mark +skbeg 1.0 0.0 0.0 +spline 0.9990087753797489 0.0 0.0001321828466218432 +spline 0.9979782091593512 0.0 0.0002741365260412735 +spline 0.9969068557635791 0.0 0.0004264835758199288 +spline 0.9957932246948061 0.0 0.0005898723955456967 +spline 0.9946357794236589 0.0 0.000764976189374184 +spline 0.9934329362271468 0.0 0.0009524914611459873 +spline 0.9921830629310853 0.0 0.001153135994925303 +spline 0.9908844775440524 0.0 0.001367646240830077 +spline 0.989535446754503 0.0 0.001596774018720059 +spline 0.9881341842683602 0.0 0.001841282440792564 +spline 0.9866788489530366 0.0 0.002101940944253337 +spline 0.985167542766593 0.0 0.002379519309983862 +spline 0.9835983076146946 0.0 0.002674780687421874 +spline 0.9819691254713504 0.0 0.002988472647273746 +spline 0.9802779118004638 0.0 0.003321317959763864 +spline 0.9785225143647212 0.0 0.003674002637238989 +spline 0.9767007086101434 0.0 0.004047162676085185 +spline 0.9748101954585755 0.0 0.004441368111425334 +spline 0.9728485932799635 0.0 0.004857105799393651 +spline 0.9708134354305149 0.0 0.005294758282188284 +spline 0.9687021638729153 0.0 0.005754580342793698 +spline 0.9665121231330085 0.0 0.006236672005476944 +spline 0.9642405538624044 0.0 0.006740947713494844 +spline 0.9618845864734133 0.0 0.007267102876028185 +spline 0.9594413058819921 0.0 0.007814893341668305 +spline 0.9569078532694137 0.0 0.008384572274999218 +spline 0.9542813168484929 0.0 0.008976386692140221 +spline 0.9515587130207037 0.0 0.009590480501001138 +spline 0.9487369855100286 0.0 0.01022687599315634 +spline 0.945813004638998 0.0 0.01088545314097124 +spline 0.942783566780977 0.0 0.01156592651642563 +spline 0.9396453939897179 0.0 0.01226781965352034 +spline 0.9363951343059824 0.0 0.01299043656646606 +spline 0.933029362394118 0.0 0.01373283033384398 +spline 0.9295445809001825 0.0 0.01449376850663881 +spline 0.9259372228246188 0.0 0.01527169514489701 +spline 0.9222036938715868 0.0 0.01606487250470437 +spline 0.9183406961706944 0.0 0.01687287443984651 +spline 0.9143451253433935 0.0 0.01769612476124379 +spline 0.9102139219133466 0.0 0.01853517829516109 +spline 0.9059440820295047 0.0 0.01939073585381203 +spline 0.9015326705041669 0.0 0.0202636679370996 +spline 0.8969768349970166 0.0 0.0211550406643361 +spline 0.8922738213174143 0.0 0.02206614403565564 +spline 0.8874209879814227 0.0 0.02299852295736582 +spline 0.8824157789065917 0.0 0.02395371951544411 +spline 0.8772555452780451 0.0 0.02493236848365839 +spline 0.871937712953194 0.0 0.02593488331140327 +spline 0.8664598353434976 0.0 0.02696171349694147 +spline 0.8608196105029857 0.0 0.02801335031976217 +spline 0.8550148967822955 0.0 0.02909033341023709 +spline 0.8490437289616155 0.0 0.03019325775840857 +spline 0.842904334811851 0.0 0.0313227811278828 +spline 0.8365951520255968 0.0 0.03247963182927922 +spline 0.8301148454519939 0.0 0.03366461679509788 +spline 0.8234623244327893 0.0 0.03487862990790976 +spline 0.8166367605901403 0.0 0.03612266041712947 +spline 0.8096376055437406 0.0 0.03739780142291998 +spline 0.8024646084903562 0.0 0.0387052583052012 +spline 0.7951178337336249 0.0 0.04004635693099488 +spline 0.7875976779783103 0.0 0.04142255150634959 +spline 0.7799048855450517 0.0 0.04283543222787684 +spline 0.7720405718469885 0.0 0.04428672144903029 +spline 0.764006100624526 0.0 0.04577762971872359 +spline 0.7558030102259701 0.0 0.04730830501029148 +spline 0.7474331767310014 0.0 0.04887871183598985 +spline 0.7388988423677872 0.0 0.05048872230075181 +spline 0.730202623188583 0.0 0.05213811155355769 +spline 0.7213475153241476 0.0 0.05382655355598901 +spline 0.7123368998493218 0.0 0.05555361719955787 +spline 0.7031745452467058 0.0 0.05731876300571855 +spline 0.69386460963093 0.0 0.05912134003410383 +spline 0.6844116396172271 0.0 0.06096058363704927 +spline 0.6748205680217986 0.0 0.06283561368188392 +spline 0.665096709423409 0.0 0.06474543346595307 +spline 0.6552457429145084 0.0 0.06668887483255358 +spline 0.6452735768378489 0.0 0.06866395997956463 +spline 0.6351863692266301 0.0 0.07066806835347454 +spline 0.6249906011976696 0.0 0.07269837521620778 +spline 0.614693065790501 0.0 0.07475186971075072 +spline 0.6043008534849249 0.0 0.07682536643411747 +spline 0.5938213360342397 0.0 0.07891551896463068 +spline 0.5832621489109076 0.0 0.08101883522205784 +spline 0.5726311722031908 0.0 0.08313169460316408 +spline 0.5619365100316617 0.0 0.0852503667620717 +spline 0.5511864687035037 0.0 0.08737103184894508 +spline 0.5403886582479288 0.0 0.08948532211318229 +spline 0.5295443536347108 0.0 0.09155082146513059 +spline 0.5186526637149406 0.0 0.093508819466527 +spline 0.5077145060100517 0.0 0.09530002448757624 +spline 0.4967358941104777 0.0 0.09688163728672797 +spline 0.4857285404238327 0.0 0.0982374692530671 +spline 0.4747053574728284 0.0 0.09935422841845784 +spline 0.4636804756705865 0.0 0.1002250959841126 +spline 0.4526703173015253 0.0 0.1008775775024013 +spline 0.4416901488525046 0.0 0.1013517069461934 +spline 0.4307531547434411 0.0 0.1016869462753451 +spline 0.4198705757551138 0.0 0.1019073957619457 +spline 0.409052474911212 0.0 0.1020175140191878 +spline 0.3983085704537707 0.0 0.102020722673854 +spline 0.3876482505857621 0.0 0.1019207302796176 +spline 0.3770805449562268 0.0 0.1017214996324819 +spline 0.366614099252437 0.0 0.1014272145731023 +spline 0.3562571530589818 0.0 0.1010422466698695 +spline 0.3460175209568611 0.0 0.1005711221509409 +spline 0.3359025767618802 0.0 0.1000184894177816 +spline 0.3259192409693631 0.0 0.09938908744743591 +spline 0.3160739728043233 0.0 0.09868769430576518 +spline 0.3063728173758031 0.0 0.0979184348849529 +spline 0.2968214287315485 0.0 0.09708468321780293 +spline 0.2874250128269072 0.0 0.09618987254191749 +spline 0.2781883198873672 0.0 0.09523752704071008 +spline 0.2691156429584259 0.0 0.09423124213006169 +spline 0.2602108189257212 0.0 0.09317466500805605 +spline 0.2514772318607602 0.0 0.09207147562350841 +spline 0.2429178186658557 0.0 0.09092536822426382 +spline 0.2345350767235326 0.0 0.08974003360267972 +spline 0.2263310734521497 0.0 0.08851914216425252 +spline 0.2183074576081409 0.0 0.08726632792547645 +spline 0.2104654721446554 0.0 0.08598517352768564 +spline 0.2028059751031133 0.0 0.08467915779876325 +spline 0.1953296475197865 0.0 0.08335057001177201 +spline 0.1880370338930814 0.0 0.08200053040199076 +spline 0.1809283348004926 0.0 0.08063031939065975 +spline 0.174003406637984 0.0 0.07924142472132756 +spline 0.167261775159455 0.0 0.0778355129107922 +spline 0.1607026499657334 0.0 0.07641440127488959 +spline 0.1543249387956431 0.0 0.07498003051488465 +spline 0.1481272670795852 0.0 0.07353443933141793 +spline 0.1421079903377829 0.0 0.07207973849062355 +spline 0.136265213681155 0.0 0.07061808770178886 +spline 0.1305968079196271 0.0 0.06915167310371734 +spline 0.1251004343249101 0.0 0.06768268854963494 +spline 0.1197735521444585 0.0 0.06621331405476247 +spline 0.1146134431840524 0.0 0.06474570036269205 +spline 0.1096172281589022 0.0 0.06328195319826324 +spline 0.1047818861828762 0.0 0.06182412023784516 +spline 0.1001042636133988 0.0 0.06037417668314067 +spline 0.0955811055906026 0.0 0.05893401958041332 +spline 0.09120912376568728 0.0 0.05750526531275962 +spline 0.08698543086186246 0.0 0.05608802103941818 +spline 0.08290724235031724 0.0 0.0546819321888603 +spline 0.07897164242539444 0.0 0.0532869240883429 +spline 0.07517559945229199 0.0 0.05190315972873338 +spline 0.07151598157745588 0.0 0.05053099744208442 +spline 0.06798957192358278 0.0 0.04917095308891824 +spline 0.06459308255058191 0.0 0.04782366605042816 +spline 0.0613231678130878 0.0 0.04648986890403303 +spline 0.05817643755043745 0.0 0.04517035971433999 +spline 0.05514962419690089 0.0 0.04386562107260177 +spline 0.0522398084218954 0.0 0.04257535245580712 +spline 0.0494440534245906 0.0 0.04129936971763946 +spline 0.04675935170961605 0.0 0.04003771916909245 +spline 0.04418263883782127 0.0 0.03879063313594722 +spline 0.04171080546394079 0.0 0.03755849017575403 +spline 0.0393407113403479 0.0 0.03634178121271874 +spline 0.03706919591366027 0.0 0.03514107852653007 +spline 0.03489308754950842 0.0 0.03395700803963984 +spline 0.0328092142437711 0.0 0.03279022610505327 +spline 0.03081442130669026 0.0 0.03164140393916078 +spline 0.02890557025739307 0.0 0.03051120484320511 +spline 0.02707954726234012 0.0 0.02940026938918174 +spline 0.02533328261072452 0.0 0.02830921044108411 +spline 0.02366379767113633 0.0 0.02723852351758408 +spline 0.02206889850930264 0.0 0.02618754886327262 +spline 0.02054690332277005 0.0 0.02515499167745248 +spline 0.01909601888035668 0.0 0.02413989782199087 +spline 0.01771434552204848 0.0 0.02314161889171025 +spline 0.01639989602578823 0.0 0.02215975790118321 +spline 0.01515061108223743 0.0 0.02119412197037715 +spline 0.0139643743690182 0.0 0.02024467901875141 +spline 0.01283928155090316 0.0 0.01931121406891053 +spline 0.01177387408157978 0.0 0.01839308238717782 +spline 0.01076660853473847 0.0 0.01748986939901837 +spline 0.00981580222714559 0.0 0.01660142415482439 +spline 0.008919651040157602 0.0 0.01572780450871212 +spline 0.00807624660018714 0.0 0.01486922804946303 +spline 0.007283593843212163 0.0 0.01402602888380527 +spline 0.006539627889841374 0.0 0.01319861868401332 +spline 0.005842231522928772 0.0 0.01238745307662587 +spline 0.005189252804380801 0.0 0.01159300300372984 +spline 0.00457877921444681 0.0 0.01081553086942471 +spline 0.004010313687738792 0.0 0.01005424080374014 +spline 0.003483699806842021 0.0 0.00930824224955492 +spline 0.002998598306054439 0.0 0.008576955474867004 +spline 0.002554508246922546 0.0 0.007860066871602116 +spline 0.002150774440356647 0.0 0.007157490155457711 +spline 0.001786588077112968 0.0 0.006469334283710064 +spline 0.0014609820866705 0.0 0.005795871881533633 +spline 0.001172825302467035 0.0 0.005137507579772312 +spline 0.0009208181859395529 0.0 0.004494745285221833 +spline 0.0007034921053932834 0.0 0.00386815318214632 +spline 0.0005192141509123521 0.0 0.003258326565700027 +spline 0.0003661999809912765 0.0 0.002665853757095631 +spline 0.0002425331721573686 0.0 0.002091281683153914 +spline 0.0001461916778060298 0.0 0.001535086295722448 +spline 7.507954461230265e-05 0.0 0.0009976486125247068 +spline 2.706178238058099e-05 0.0 0.0004792375441569564 +spline 0.0 0.0 -2e-05 +spline -1.070830957182994e-05 0.0 -0.000519598311385809 +skend +skbeg -1.070830957182994e-05 0.0 -0.000519598311385809 +spline 3.968998753512799e-05 0.0 -0.001037509830861938 +spline 0.0001544840568354694 0.0 -0.001567077700830471 +spline 0.0003330005974600307 0.0 -0.002102362798194595 +spline 0.0005713982330428165 0.0 -0.002639405904449688 +spline 0.000863943689447444 0.0 -0.003176750825022636 +spline 0.001204041187529012 0.0 -0.003715392396788188 +spline 0.001584856681617041 0.0 -0.004258373275115059 +spline 0.002003405523994527 0.0 -0.004807438615428181 +spline 0.002460239577347682 0.0 -0.005362228585298055 +spline 0.002955678937385457 0.0 -0.005922700898486172 +spline 0.003489668175242838 0.0 -0.006489331456856403 +spline 0.004061778904578593 0.0 -0.007063212671762736 +spline 0.004671377979317589 0.0 -0.007645944172044386 +spline 0.005318786434080808 0.0 -0.008238403728316477 +spline 0.006004727102922545 0.0 -0.008841199225460172 +spline 0.0067298150747689 0.0 -0.009455204787190708 +spline 0.007494532383332695 0.0 -0.01008161458290012 +spline 0.008299574437578642 0.0 -0.0107215277922225 +spline 0.009146509207501577 0.0 -0.01137505520968715 +spline 0.01003706772614734 0.0 -0.01204217940044264 +spline 0.01097296958479492 0.0 -0.01272293881869857 +spline 0.0119559222904556 0.0 -0.01341745846879269 +spline 0.01298760891938634 0.0 -0.01412597577692548 +spline 0.01406967688231738 0.0 -0.01484887207075198 +spline 0.01520372580958288 0.0 -0.01558670854751259 +spline 0.01639128900162343 0.0 -0.01634026376459482 +spline 0.0176338259386493 0.0 -0.01711058453748232 +spline 0.01893276947827469 0.0 -0.01789890885157339 +spline 0.02028998838784297 0.0 -0.01870590471118367 +spline 0.021707570020899 0.0 -0.01953199144915441 +spline 0.02318761572011189 0.0 -0.02037767688026184 +spline 0.02473223242752406 0.0 -0.02124357914813543 +spline 0.02634352350690856 0.0 -0.02213045071712301 +spline 0.02802357758366764 0.0 -0.02303920636682479 +spline 0.02977446392883618 0.0 -0.02397093952821648 +spline 0.03159849412509542 0.0 -0.02492643072524681 +spline 0.0334983142711 0.0 -0.02590593498173195 +spline 0.03547664189528116 0.0 -0.02690969438981583 +spline 0.03753622984868726 0.0 -0.02793797255124282 +spline 0.03967986724462401 0.0 -0.0289910692587028 +spline 0.04191037114087689 0.0 -0.03006933277308035 +spline 0.04423057877584989 0.0 -0.03117317503379109 +spline 0.04664333885113084 0.0 -0.03230308927043829 +spline 0.04915150201408446 0.0 -0.03345967034493388 +spline 0.05175790968774128 0.0 -0.03464363769800025 +spline 0.05446538326601325 0.0 -0.03585586210193234 +spline 0.05727670419236906 0.0 -0.03709739228004851 +spline 0.06019461042531121 0.0 -0.03836949304733217 +spline 0.06322176993077168 0.0 -0.03967367773027207 +spline 0.06636086616124724 0.0 -0.0410115109689275 +spline 0.06961512477893321 0.0 -0.04238334465505924 +spline 0.07298802080985184 0.0 -0.04378895083978962 +spline 0.07648307254935904 0.0 -0.04522797839743766 +spline 0.08010383602697499 0.0 -0.04669994202852096 +spline 0.08385389906508349 0.0 -0.04820420968064849 +spline 0.0877368751514413 0.0 -0.04973998934481379 +spline 0.09175639560326551 0.0 -0.05130631460027155 +spline 0.09591610193599359 0.0 -0.05290202965894086 +spline 0.1002196365063859 0.0 -0.05452577440089731 +spline 0.1046705744454653 0.0 -0.05617612670893558 +spline 0.1092723383444706 0.0 -0.05785179941951395 +spline 0.1140282739289971 0.0 -0.05955140744787053 +spline 0.118941646031923 0.0 -0.06127343076817566 +spline 0.1240156333302364 0.0 -0.06301621682741695 +spline 0.1292532980134544 0.0 -0.06477797531587161 +spline 0.1346575774499731 0.0 -0.06655678189702584 +spline 0.1402312646816999 0.0 -0.06835057926331453 +spline 0.145976992038676 0.0 -0.07015718054064093 +spline 0.1518972043156699 0.0 -0.07197427078031515 +spline 0.1579941531465652 0.0 -0.0737994164437385 +spline 0.1642698678733839 0.0 -0.07563006887560098 +spline 0.1707261383222463 0.0 -0.07746357292336253 +spline 0.1773644951395592 0.0 -0.07929717613067996 +spline 0.1841861901734267 0.0 -0.08112803925358168 +spline 0.1911921770958491 0.0 -0.08295324809596143 +spline 0.1983830924429242 0.0 -0.08476982663221334 +spline 0.2057592372495541 0.0 -0.08657475136158772 +spline 0.2133205881761383 0.0 -0.08836486367457544 +spline 0.2210671665631215 0.0 -0.09013508253700149 +spline 0.228999015720709 0.0 -0.09187838020338955 +spline 0.2371157858805631 0.0 -0.09358714724072138 +spline 0.2454167104818773 0.0 -0.0952532386592112 +spline 0.253900566453729 0.0 -0.09686797090938096 +spline 0.2625656378594985 0.0 -0.09842212527853032 +spline 0.271409674155087 0.0 -0.0999059567496887 +spline 0.2804298533150048 0.0 -0.1013092110802701 +spline 0.2896227369931855 0.0 -0.1026211487668667 +spline 0.2989842308841478 0.0 -0.1038305791058019 +spline 0.3085095401897754 0.0 -0.1049259036994803 +spline 0.3181931282896007 0.0 -0.105895171592076 +spline 0.3280286697423238 0.0 -0.1067262260763325 +spline 0.3380089354060737 0.0 -0.1074080118622318 +spline 0.3481258546850401 0.0 -0.1079304569375507 +spline 0.3583706075243047 0.0 -0.1082835313684722 +spline 0.3687336192634914 0.0 -0.1084572831240863 +spline 0.3792045587801731 0.0 -0.1084419108205368 +spline 0.3897723402659258 0.0 -0.1082278430527005 +spline 0.4004251345866191 0.0 -0.1078058241365513 +spline 0.4111503886251916 0.0 -0.1071670056284606 +spline 0.4219348501840513 0.0 -0.1063030431992751 +spline 0.4327646048911357 0.0 -0.1052061977433087 +spline 0.443625192867815 0.0 -0.1038699762176675 +spline 0.4545027714111136 0.0 -0.1022964297709617 +spline 0.4653844817568922 0.0 -0.1004941785157118 +spline 0.4762579333989129 0.0 -0.09847261810728107 +spline 0.487112462668105 0.0 -0.0962476912693429 +spline 0.4979419091897664 0.0 -0.09385246112821385 +spline 0.5087423665477697 0.0 -0.09132347137228447 +spline 0.5195111236195169 0.0 -0.08869676363149047 +spline 0.5302441844780578 0.0 -0.08599923861877558 +spline 0.5409366610565618 0.0 -0.08325192565542588 +spline 0.5515839887679104 0.0 -0.08047553197225492 +spline 0.562180905404066 0.0 -0.07768683601008168 +spline 0.5727202659770608 0.0 -0.07489449597745233 +spline 0.5831948336774904 0.0 -0.0721059815371694 +spline 0.5935975605653802 0.0 -0.06932857477744805 +spline 0.6039215953241852 0.0 -0.06656932633102096 +spline 0.6141602911177806 0.0 -0.06383501482372582 +spline 0.6243072128140815 0.0 -0.0611321101746916 +spline 0.6343561437346243 0.0 -0.05846674096651958 +spline 0.6443010934245192 0.0 -0.05584466568542402 +spline 0.654136304929079 0.0 -0.05327124837348633 +spline 0.6638562595587845 0.0 -0.05075142887031545 +spline 0.6734555608926294 0.0 -0.04828922475404752 +spline 0.68292890428342 0.0 -0.04588754953176419 +spline 0.6922712725108067 0.0 -0.04354892022017716 +spline 0.7014779591140057 0.0 -0.04127551700651144 +spline 0.7105445749562107 0.0 -0.03906918592140247 +spline 0.7194670535507448 0.0 -0.03693144395959395 +spline 0.728241655246941 0.0 -0.03486348644439229 +spline 0.7368649696308267 0.0 -0.03286619659011231 +spline 0.7453339170193678 0.0 -0.03094015684006354 +spline 0.7536457485798926 0.0 -0.02908566187588805 +spline 0.7617980450829666 0.0 -0.02730273307059344 +spline 0.7697887143667543 0.0 -0.02559113414133143 +spline 0.7776159889025231 0.0 -0.0239503942764878 +spline 0.7852784328772136 0.0 -0.02237988510919161 +spline 0.7927749277899079 0.0 -0.02087880339244491 +spline 0.8001046562246066 0.0 -0.0194461465682929 +spline 0.8072670937708214 0.0 -0.01808073092426795 +spline 0.8142620001428573 0.0 -0.01678121029499591 +spline 0.8210894094564424 0.0 -0.0155460945599613 +spline 0.827749619749582 0.0 -0.01437376778086368 +spline 0.834243181905752 0.0 -0.01326250582754034 +spline 0.8405708878986454 0.0 -0.01221049340110895 +spline 0.8467337584631576 0.0 -0.01121584034464276 +spline 0.85273303061958 0.0 -0.01027659710009958 +spline 0.8585701448006564 0.0 -0.009390769301301755 +spline 0.8642467317791884 0.0 -0.008556331430968605 +spline 0.8697645994865493 0.0 -0.007771239504196711 +spline 0.8751257198057465 0.0 -0.007033442755898926 +spline 0.8803322154188231 0.0 -0.006340894323048289 +spline 0.8853863467852825 0.0 -0.00569156092448408 +spline 0.8902905149556262 0.0 -0.005083552914446419 +spline 0.8950472829366074 0.0 -0.00451546184692306 +spline 0.8996593119542231 0.0 -0.003985928633443964 +spline 0.9041293286400948 0.0 -0.003493525982262833 +spline 0.9084601198891991 0.0 -0.003036774954622432 +spline 0.9126545258367009 0.0 -0.002614160204129024 +spline 0.916715429351497 0.0 -0.002224144055931803 +spline 0.9206457500475196 0.0 -0.001865178668875309 +spline 0.9244484363630523 0.0 -0.001535717317537781 +spline 0.9281264607221862 0.0 -0.001234253989142401 +spline 0.9316828134372723 0.0 -0.0009593507534290472 +spline 0.9351204907253561 0.0 -0.0007095851580201726 +spline 0.9384424881765357 0.0 -0.0004835514176657564 +spline 0.9416517951144666 0.0 -0.000279867781856104 +spline 0.9447513886398117 0.0 -9.718282734864164e-05 +spline 0.9477442309699601 0.0 6.581944159388359e-05 +spline 0.9506332610484662 0.0 0.0002104150724955854 +spline 0.9534213925108137 0.0 0.0003378368501247392 +spline 0.9561115089547733 0.0 0.0004492715658608403 +spline 0.9587064601295556 0.0 0.0005458580111912734 +spline 0.9612090584428907 0.0 0.0006286855844429949 +spline 0.9636220774576785 0.0 0.0006987340543540364 +spline 0.9659482569956704 0.0 0.0007565156074196434 +spline 0.9681902870752733 0.0 0.0008024051444539233 +spline 0.9703508003831635 0.0 0.0008368525695455863 +spline 0.9724323725670436 0.0 0.0008603668483639414 +spline 0.9744375225228721 0.0 0.0008735011788687537 +spline 0.9763687126541365 0.0 0.0008768402005455661 +spline 0.978228349095837 0.0 0.0008709890168437007 +spline 0.9800187819161187 0.0 0.0008565638293025258 +spline 0.9817423066024864 0.0 0.0008341839823327035 +spline 0.9834011592783564 0.0 0.0008044653654583872 +spline 0.984997524228127 0.0 0.000768014772539381 +spline 0.9865335291756596 0.0 0.0007254254046528674 +spline 0.9880112468246192 0.0 0.0006772731699272991 +spline 0.9894326951380275 0.0 0.0006241137598995575 +spline 0.9907998376773224 0.0 0.0005664803912198834 +spline 0.9921145839806025 0.0 0.000504882126302716 +spline 0.9933787900062063 0.0 0.0004398026937263032 +spline 0.9945942586228987 0.0 0.0003716997389508177 +spline 0.9957627401747287 0.0 0.0003010044410611266 +spline 0.9968859330904163 0.0 0.0002281214408622816 +spline 0.9979654845460086 0.0 0.0001534290300594675 +spline 0.9990029912109952 0.0 7.727955486242507e-05 +skend +group +store s809airfoil + +#============================================================================================ +# START OF THE CSM SCRIPT +# restoring sketches | s809 +#============================================================================================ +restore s809airfoil +join + +# collecting leading edge point +dimension wleading 1 3 1 +dimension wutrailing 1 3 1 +dimension wltrailing 1 3 1 + +set xmin @xmax +set zmin @zmax +set zmax @zmin +set nNodes @nnode +patbeg inode nNodes + evaluate node @ibody inode + IFTHEN @edata[1] LT xmin + set xmin @edata[1] + set wleading "xmin;@edata[2];@edata[3];" + set leadingNode inode + ENDIF + IFTHEN inode NE leadingNode + IFTHEN @edata[3] GT zmax + set zmax @edata[3] + set wutrailing "@edata[1];@edata[2];zmax;" + ENDIF + IFTHEN @edata[3] LT zmin + set zmin @edata[3] + set wltrailing "@edata[1];@edata[2];zmin;" + ENDIF + ENDIF +patend + +combine +store airfoilFace + +#RESTORING THE AIRFOIL FACE FOR EXTRUSION +#============================================================================================ +restore airfoilFace + +extrude 0 span 0 + +#ADDING EDGE ATTRIBUTES OF QUASI MODEL +#-------------------------------------------------------------------------------------------- +dimension ySymm 2 1 +set ySymm "0;span;" +patbeg i 2 + udparg edgeAttr attrname $edgeName attrstr $symmetry + udprim edgeAttr xyzs "wleading[1];ySymm[i];wleading[3];wutrailing[1];ySymm[i];wutrailing[3];" + udparg edgeAttr attrname $edgeName attrstr $symmetry + udprim edgeAttr xyzs "wleading[1];ySymm[i];wleading[3];wltrailing[1];ySymm[i];wltrailing[3];" +patend + +udparg edgeAttr attrname $edgeName attrstr $wingleadingEdge +udprim edgeAttr xyzs "wleading[1];wleading[2];wleading[3];wleading[1];span;wleading[3];" +udparg edgeAttr attrname $edgeName attrstr $wingtrailingEdge +udprim edgeAttr xyzs "wutrailing[1];wutrailing[2];wutrailing[3];wutrailing[1];span;wutrailing[3];" +udparg edgeAttr attrname $edgeName attrstr $wingtrailingEdge +udprim edgeAttr xyzs "wltrailing[1];wltrailing[2];wltrailing[3];wltrailing[1];span;wltrailing[3];" + +store quasiBody + +#============================================================================================ +restore quasiBody +attribute faceName $wing +attribute groupName $wing +set nWingFaces @nface +set sumWingArea @area + +#finding min area face as trailing edge face | wing +#-------------------------------------------------- +set minArea sumWingArea +patbeg i nWingFaces + select face i + IFTHEN @area LT minArea + set minArea @area + set trailingFace i + ENDIF +patend +select face trailingFace +attribute faceName $wingTrailing +attribute groupName $wing + +END diff --git a/examples/Quick_Starts/S809/s809Case.json b/examples/Quick_Starts/S809/s809Case.json new file mode 100644 index 0000000..b8fe459 --- /dev/null +++ b/examples/Quick_Starts/S809/s809Case.json @@ -0,0 +1,61 @@ +{ + "geometry": { + "refArea": 0.01, + "momentCenter": [0.25,0,0], + "momentLength": [1,1,1] + }, + "volumeOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Mach"] + }, + "surfaceOutput" : { + "outputFormat" : "tecplot", + "animationFrequency" : -1, + "outputFields": ["primitiveVars", "Cp", "Cf"] + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-11, + "linearIterations": 35, + "kappaMUSCL": 0.33, + "orderOfAccuracy": 2 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "absoluteTolerance": 1e-10, + "linearIterations": 25, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "freestream": { + "Reynolds": 2e+06, + "Mach": 0.15, + "Temperature": 293.15, + "alphaAngle": 5.13, + "betaAngle": 0 + }, + "boundaries": { + "fluid/symmetric-1": { + "type": "SlipWall" + }, + "fluid/symmetric-2": { + "type": "SlipWall" + }, + "fluid/wing": { + "type": "NoSlipWall" + }, + "fluid/farfield": { + "type": "Freestream" + } + }, + "timeStepping": { + "physicalSteps": 1, + "timeStepSize": "inf", + "maxPseudoSteps": 5000, + "CFL": { + "initial": 200, + "final": 200, + "rampSteps": 100 + } + } +} diff --git a/examples/Quick_Starts/S809/s809SurfaceMesh.json b/examples/Quick_Starts/S809/s809SurfaceMesh.json new file mode 100644 index 0000000..fd98185 --- /dev/null +++ b/examples/Quick_Starts/S809/s809SurfaceMesh.json @@ -0,0 +1,25 @@ +{ + "maxEdgeLength": 0.58, + "curvatureResolutionAngle": 10, + "growthRate": 1.08, + "edges": { + "wingleadingEdge": { + "type": "aniso", + "method": "height", + "value": 4e-4 + }, + "wingtrailingEdge": { + "type": "aniso", + "method": "height", + "value": 4e-4 + }, + "symmetry": { + "type": "projectAnisoSpacing" + } + }, + "faces": { + "wing": { + "maxEdgeLength": 0.40 + } + } +} diff --git a/examples/Quick_Starts/S809/s809VolumeMesh.json b/examples/Quick_Starts/S809/s809VolumeMesh.json new file mode 100644 index 0000000..4a22281 --- /dev/null +++ b/examples/Quick_Starts/S809/s809VolumeMesh.json @@ -0,0 +1,52 @@ +{ + "refinementFactor": 1.0, + "farfield": { + "type": "quasi-3d" + }, + "refinement": [ + { + "type": "cylinder", + "radius": 1.1, + "length": 1.0, + "spacing": 0.08, + "axis": [0,1,0], + "center": [0.7,0.5,0] + }, + { + "type": "cylinder", + "radius": 2.2, + "length": 1.0, + "spacing": 0.13, + "axis": [0,1,0], + "center": [0.7,0.5,0] + }, + { + "type": "cylinder", + "radius": 3.3, + "length": 1.0, + "spacing": 0.2, + "axis": [0,1,0], + "center": [0.7,0.5,0] + }, + { + "type": "cylinder", + "radius": 4.5, + "length": 1.0, + "spacing": 0.25, + "axis": [0,1,0], + "center": [0.7,0.5,0] + }, + { + "type": "cylinder", + "radius": 6.5, + "length": 14.5, + "spacing": 0.29, + "axis": [-1,0,0], + "center": [2,0.5,0] + } + ], + "volume": { + "firstLayerThickness": 4.29e-06, + "growthRate": 1.04 + } +} diff --git a/examples/Quick_Starts/S809/submit_case_from_download.py b/examples/Quick_Starts/S809/submit_case_from_download.py new file mode 100644 index 0000000..14d0954 --- /dev/null +++ b/examples/Quick_Starts/S809/submit_case_from_download.py @@ -0,0 +1,47 @@ +"""Case submission using automated meshing and structured pre-generated mesh case submission from mesh download""" + +import os.path +from urllib.request import urlretrieve + +import flow360 as fl + +# inputs for structured mesh download +URL = "https://simcloud-public-1.s3.amazonaws.com/s809/s809structured.cgns" +MESH_FILENAME = "s809structured.cgns" + +case_name_list = [] + +params = fl.SurfaceMeshingParams("s809SurfaceMesh.json") +surface_mesh = fl.SurfaceMesh.create( + "s809.csm", params=params, name="NREL_S809_Surface" +) +surface_mesh = surface_mesh.submit() + +params = fl.VolumeMeshingParams("s809VolumeMesh.json") +volume_mesh = surface_mesh.create_volume_mesh("NREL_S809_Volume", params=params) +volume_mesh = volume_mesh.submit() + +params = fl.Flow360Params("s809Case.json") + +# submit case +case = fl.Case.create("NREL_S809_Automated_Meshing", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + +# submit mesh +volume_mesh2 = fl.VolumeMesh.from_file(MESH_FILENAME, name="S809_Structured_Mesh") +volume_mesh2 = volume_mesh2.submit() + +# submit case +case2 = fl.Case.create("NREL_S809_Structured", params, volume_mesh2.id) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/S809/submit_case_from_id.py b/examples/Quick_Starts/S809/submit_case_from_id.py new file mode 100644 index 0000000..6b10bd2 --- /dev/null +++ b/examples/Quick_Starts/S809/submit_case_from_id.py @@ -0,0 +1,37 @@ +"""Case submission using automated meshing and structured pre-generated mesh case submission from mesh ID""" + +import flow360 as fl + +# mesh ID for structured mesh +MESH_ID = "0ab89ce3-33e0-4d4e-bd4a-7249da3cd9c3" + +case_name_list = [] + +params = fl.SurfaceMeshingParams("s809SurfaceMesh.json") +surface_mesh = fl.SurfaceMesh.create( + "s809.csm", params=params, name="NREL_S809_Surface" +) +surface_mesh = surface_mesh.submit() + +params = fl.VolumeMeshingParams("s809VolumeMesh.json") +volume_mesh = surface_mesh.create_volume_mesh("NREL_S809_Volume", params=params) +volume_mesh = volume_mesh.submit() + +params = fl.Flow360Params("s809Case.json") + +# submit case +case = fl.Case.create("NREL_S809_Automated_Meshing", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + + +# submit case +case2 = fl.Case.create("NREL_S809_Structured", params, MESH_ID) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/XV15/Flow360.json b/examples/Quick_Starts/XV15/Flow360.json new file mode 100644 index 0000000..5377358 --- /dev/null +++ b/examples/Quick_Starts/XV15/Flow360.json @@ -0,0 +1,66 @@ +{ + "geometry" : { + "refArea" : 45.604, + "momentCenter" : [0, 0, 0], + "momentLength" : [3.81, 3.81, 3.81] + }, + "volumeOutput" : { + "outputFormat" : "tecplot", + "outputFields": ["primitiveVars", "T","Cp", "Mach", "qcriterion", "VelocityRelative"] + }, + "surfaceOutput" : { + "outputFormat" : "tecplot", + "outputFields": ["primitiveVars", "Cp", "Cf","CfTangent", "CfNormal","nodeForcesPerUnitArea"] + }, + "navierStokesSolver" : { + "absoluteTolerance" : 1e-9, + "relativeTolerance" : 1e-2, + "linearIterations" : 35, + "kappaMUSCL" : -1.0, + "orderOfAccuracy" : 2, + "updateJacobianFrequency" : 4, + "equationEvalFrequency" : 1 + }, + "turbulenceModelSolver" : { + "modelType" : "SpalartAllmaras", + "absoluteTolerance" : 1e-8, + "relativeTolerance" : 1e-2, + "linearIterations" : 25, + "kappaMUSCL" : -1.0, + "DDES" : true, + "orderOfAccuracy" : 2, + "updateJacobianFrequency" : 4, + "equationEvalFrequency" : 1, + "rotationCorrection" : true + }, + "freestream" : + { + "muRef" : 4.29279e-08, + "Mach" : 1.46972e-02, + "MachRef" : 0.70, + "Temperature" : 288.15, + "alphaAngle" : -90.0, + "betaAngle" : 0.0 + }, + "boundaries" : { + "farField/farField" : { "type" : "Freestream" }, + "innerRotating/blade" : { "type" : "NoSlipWall" } + }, + "volumeZones":{ + "innerRotating":{ + "referenceFrame":{ + "axisOfRotation" : [0,0,-1], + "centerOfRotation" : [0,0,0], + "omegaRadians" : 1.84691e-01 + } + } + }, + "timeStepping" : { + "timeStepSize" : 2.83500e-01, + "physicalSteps" : 600, + "maxPseudoSteps" : 35, + "CFL" : { + "type": "adaptive" + } + } +} diff --git a/examples/Quick_Starts/XV15/README.md b/examples/Quick_Starts/XV15/README.md new file mode 100644 index 0000000..54d8e74 --- /dev/null +++ b/examples/Quick_Starts/XV15/README.md @@ -0,0 +1,13 @@ +The following example, launches the XV-15 Quick-start case. + +To run the demo case follow these steps: + +1. Run `python submit_cases_from_downloads.py` -> this script will download the XV15 mesh, and upload it to the Flexcompute servers. The case will also be submitted. Alternatively the script `submit_cases_from_id.py` can also be used to run the case from a mesh already uploaded to Flexcompute servers. + +2. Run `python download_data.py` -> this script will download the csv files containing the loads and residual histories. + +3. Run `python convergence_plots.py` -> this script will plot the load and residual convergence histories. + +4. Run `python download_plot_sectional_forces.py` -> this script will download and plot the sectional loads. + +5. Run `download_vis_figures.py` -> this script will download Cp, Cf and streamline visualizations to the vis_figures folder. diff --git a/examples/Quick_Starts/XV15/convergence_plots.py b/examples/Quick_Starts/XV15/convergence_plots.py new file mode 100644 index 0000000..8b7ad1a --- /dev/null +++ b/examples/Quick_Starts/XV15/convergence_plots.py @@ -0,0 +1,92 @@ +"""Plot the loads and residuals convergence plots for XV-15 quick-start""" + +import os + +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["CFz", "CMz"] +residuals = ["0_cont", "1_momx", "2_momy", "3_momz", "4_energ", "5_nuHat"] +figures = [] +axes = [] + + +def add_accum_pseudo_step(history): + "Compute the accumulated pseudo-step" + pseudo_steps = history["pseudo_step"] + accum = [] + accum.append(0) + for i in range(1, len(pseudo_steps)): + if pseudo_steps[i] > pseudo_steps[i - 1]: + accum.append(accum[-1] + abs(pseudo_steps[i] - pseudo_steps[i - 1])) + else: + accum.append(accum[-1] + 1) + history["accum_pseudo_step"] = accum + + +def plot_loads(data, plot_name): + """Plot the loads""" + x = data["accum_pseudo_step"] + for ax, load in zip(axes, loads): + ax.plot(x, data[load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Pseudo step") + ax.grid(which="major", color="gray") + + +def plot_residuals(res, plot_name): + """Plot the residuals""" + x = data["accum_pseudo_step"] + for ax, res in zip(axes, residuals): + for res in residuals: + ax.semilogy(x, data[res], label=plot_name + " " + res) + ax.set_ylabel("Residuals") + ax.legend(fontsize="8") + ax.set_title("XV-15 - Quick-Start") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -2)) + ax.set_ylim([1e-9, 1e-2]) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +# calculate and plot loads convergence histories +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "total_forces_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + add_accum_pseudo_step(data) + plot_loads(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) + +for ax in axes: + ax.cla() + + +# plot residual convergence histories +fig, ax = plt.subplots(figsize=(8, 6)) +figures.append(fig) +axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), case_name, "nonlinear_residual_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + add_accum_pseudo_step(data) + plot_residuals(data, case_name) + +figures[0].savefig(os.path.join(dir_path, "Residuals.png"), dpi=500) diff --git a/examples/Quick_Starts/XV15/download_data.py b/examples/Quick_Starts/XV15/download_data.py new file mode 100644 index 0000000..550e0b4 --- /dev/null +++ b/examples/Quick_Starts/XV15/download_data.py @@ -0,0 +1,28 @@ +"""Download the results for the XV-15 Quick start""" + +import os + +from flow360 import MyCases + +# read in case_name_list +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + # download the files + case.results.download( + nonlinear_residuals=True, + surface_forces=True, + total_forces=True, + destination=case_folder, + ) diff --git a/examples/Quick_Starts/XV15/download_plot_sectional_forces.py b/examples/Quick_Starts/XV15/download_plot_sectional_forces.py new file mode 100644 index 0000000..f0ce56c --- /dev/null +++ b/examples/Quick_Starts/XV15/download_plot_sectional_forces.py @@ -0,0 +1,63 @@ +"""Plot the sectional loads for the XV-15 rotor quick-start case""" + +import os + +import matplotlib.pyplot as plt +import pandas as pd +from flow360 import MyCases + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +loads = ["blade_CFz_per_span", "blade_CFx_per_span"] +figures = [] +axes = [] + + +def plot_sectional_forces(data, plot_name): + """Plot the sectional loads""" + for ax, load in zip(axes, loads): + ax.plot(data["Y"], data["innerRotating/" + load], label=plot_name) + ax.set_ylabel(load) + ax.legend() + ax.set_xlabel("Y") + ax.grid(which="major", color="gray") + ax.set_xlim(0, 4) + if "CFz" in load: + ax.set_ylim(-0.002, 0.01) + + +# read in case_name_list + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == case_name: + break + print(case.name) + forces = "results/postprocess/forceDistribution.csv" + # print(case.results) + case._download_file(forces, to_folder=case_folder) + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +# initialize figures & axes +for load in loads: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + +for case_name in case_name_list: + csv_path = os.path.join(os.getcwd(), f"{case_name}", "forceDistribution.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + plot_sectional_forces(data, case_name) + +for i, load in enumerate(loads): + figures[i].savefig(os.path.join(dir_path, load + ".png"), dpi=500) diff --git a/examples/Quick_Starts/XV15/download_vis_figures.py b/examples/Quick_Starts/XV15/download_vis_figures.py new file mode 100644 index 0000000..b91ed37 --- /dev/null +++ b/examples/Quick_Starts/XV15/download_vis_figures.py @@ -0,0 +1,70 @@ +"""Downloads visualizations of surface CP, CF and streamlines""" + +import os + +from flow360 import MyCases +from PIL import Image + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +fields = ["Cp", "Cf", "Fv"] + + +def fetch_png(case, field, res="H"): + """Download the required figures from Flexcompute servers""" + # download the legend i.e. color bar + case_name = case.name + os.makedirs("visualize", exist_ok=True) + + legend = f"visualize/{field}Legend.png" + case._download_file(legend, to_file=legend) + + # list all available theta and phi + view_angles = [(0, 0), (180, 0)] + for theta in [60, 120]: + for phi in range(0, 360, 90): + view_angles.append((theta, phi)) + # download the contour + axis files + for theta, phi in view_angles: + fname = f"{theta:03d}_{phi:03d}.png" + contour = f"visualize/{field}_{res}_{fname}" + axis = f"visualize/Ax_{fname}" + case._download_file(contour, to_file=contour) + case._download_file(axis, to_file=axis) + # load and overlap contour + axis + legend + img_contour = Image.open(contour).convert("RGBA") + img_axis = Image.open(axis) + img_axis = img_axis.resize((img_axis.width * 3, img_axis.height * 3)) + img_axis = img_axis.convert("RGBA") + img_legend = Image.open(legend).convert("RGBA") + background = Image.new("RGBA", img_contour.size, (67, 100, 200)) + img_contour.paste(img_axis, (0, img_contour.height - img_axis.height), img_axis) + img_contour.paste( + img_legend, + (-int(0.1 * img_contour.height), int(0.1 * img_contour.height)), + img_legend, + ) + background.paste(img_contour, (0, 0), img_contour) + background.save( + f"vis_figures/{case_name}_{field}_{res}_{theta:03d}_{phi:03d}_final.png" + ) + + +# set output directory +dir_path = os.path.join(os.getcwd(), "vis_figures") +os.makedirs(dir_path, exist_ok=True) + +case = None +my_cases = MyCases(limit=None) + +for case_name in case_name_list: + case_folder = os.path.join(os.getcwd(), case_name) + os.makedirs(case_folder, exist_ok=True) + # Find the latest case with the name corresponding to the name in case_name_list + for case in my_cases: + if case.name == case_name: + break + print(case.name) + for field in fields: + fetch_png(case, field) diff --git a/examples/Quick_Starts/XV15/submit_case_from_downloads.py b/examples/Quick_Starts/XV15/submit_case_from_downloads.py new file mode 100644 index 0000000..7319f8e --- /dev/null +++ b/examples/Quick_Starts/XV15/submit_case_from_downloads.py @@ -0,0 +1,32 @@ +"""Case submission through mesh download and upload onto Flexcompute servers""" + +import os.path +from urllib.request import urlretrieve + +import flow360 as fl + +case_name_list = [] + +# download meshes to the current directory + +URL = "https://simcloud-public-1.s3.amazonaws.com/xv15/XV15_Hover_ascent_coarse_v2.cgns" +MESH_FILENAME = "XV15_Hover_ascent_coarse_v2.cgns" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="XV15_Mesh") +volume_mesh = volume_mesh.submit() + +# submit case +params = fl.Flow360Params("Flow360.json") +case = fl.Case.create("XV15_Quick_Start", params, volume_mesh.id) +case = case.submit() + +case_name_list.append(case.name) + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n") diff --git a/examples/Quick_Starts/XV15/submit_case_from_id.py b/examples/Quick_Starts/XV15/submit_case_from_id.py new file mode 100644 index 0000000..6001102 --- /dev/null +++ b/examples/Quick_Starts/XV15/submit_case_from_id.py @@ -0,0 +1,21 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID = "cfd9dbc1-367e-4737-bdb0-ae6b2622dfaf" + +# submit case + +params = fl.Flow360Params("Flow360.json") +case = fl.Case.create("XV15_Quick_Start", params, MESH_ID) +case = case.submit() + +case_name_list.append(case.name) + +# dump case name for use in download and post-processing scripts + +with open("case_name_list.dat", "w", encoding="utf-8") as f: + for line in case_name_list: + f.write(f"{line}\n")