From a83b53e8bec0304d44853f79213f77921c838a1c Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 25 Jul 2023 17:32:08 +0100 Subject: [PATCH 01/14] Wall_Model_Example --- examples/Wall_Model/.Download_Data.py.swp | Bin 0 -> 12288 bytes examples/Wall_Model/Convergence_Plots.py | 113 ++++++++++++++++++++++ examples/Wall_Model/Download_Data.py | 29 ++++++ examples/Wall_Model/Files.py | 15 +++ examples/Wall_Model/README | 11 +++ examples/Wall_Model/Submit_Cases.py | 44 +++++++++ 6 files changed, 212 insertions(+) create mode 100644 examples/Wall_Model/.Download_Data.py.swp create mode 100644 examples/Wall_Model/Convergence_Plots.py create mode 100644 examples/Wall_Model/Download_Data.py create mode 100644 examples/Wall_Model/Files.py create mode 100644 examples/Wall_Model/README create mode 100644 examples/Wall_Model/Submit_Cases.py diff --git a/examples/Wall_Model/.Download_Data.py.swp b/examples/Wall_Model/.Download_Data.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..5f043c7f379fd12223c146189a1730441597902c GIT binary patch literal 12288 zcmeI2&ubGw6vwAtwJLhhi!dgKB#>^?7OgD=8qx#`X(CChLa57hcam&7yAyUMjRAlB z3-vGXFX-RkpWwxd;>D|8^y0;fZ#LOxQ;SmYBD{fbcX#GH@4flV>>+gb3y-$8=>uzt zK)X)J(@$^R#`^Kx@E#$$Cw->Oz@OXLxA5d)Yhh`1VQqD(aK8WL*tl38C@p;++Kqt@ zIdgi8kC_nmwsg6$t6spw;-(x1LNeFhWSUw1(fI+f7YQJN3lNwmE6d}zGo89iZ{FCw zz+AK<0VIF~kN^@u0!RP}AOR%szZ1~?Ir0h?acQ!UJCp0&nd{^cFGv6hAOR$R1dsp{ zKmter2_OL^fCP}he@KA2gtRXc@)czM{~!PU|8b3w&!7{~YtS)h9kd4eewC1KppT#r zpcBvw&~s21)B$aP2LWEko+~+g`RWcs@>V9@+vhHp4w%nru^2tn;lAc6-S+mT@l6?~P*aINvdyiUj;7&*XE(|$nC7s=$U5|NFY1h< zJ2Hgr>dV0Of-V4>jzCD`kMo`u2$Xzw$Xzc~Gm!W*sLqy$0CFcB@F^=3WlZucV+aMi z=M3E}Y)EHX#T;=JD&Cv65biPsImw?}0|0M5>7wMjcT%nrf%WRTHPec@^01<{0v zitNKCW|C7Zm+4HNX2ML4G8IjSlxY*eRF}p$)s_xdSHbqh-rcM<&qZ zRj~n-!&PEHOAW@^ZWA_?KJ5rOT)AJMp5K?Dj*-obS&oFkfCt(#3yiI0xR1}Xd8f!E NL>$rZ5pkzf0 and (not key.isspace()): + data[key.strip()].append(float(value)) + return data + +def computeCLCD(data): + CL0 = np.add(data['Windsor_CL'], data['Windsor_rear_CL']) + data['CL'] = np.add(data['Windsor_supports_CL'], CL0) + CD0 = np.add(data['Windsor_CD'], data['Windsor_rear_CD']) + data['CD'] = np.add(data['Windsor_supports_CD'], CD0) + + + +def plotLoads(data, caseName, plotName): + axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) + axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) + axes[0].set_ylabel('CL'); + axes[1].set_ylabel('CD'); + axes[0].set_ylim(-0.2, -0.1); + axes[1].set_ylim(0.25, 0.45); + + for i in range(0,2): + axes[i].legend() + axes[i].set_xlabel('Pseudo step'); + axes[i].grid(which='major', color='gray') + +def plotResiduals(res, caseName, plotName): + x = res['pseudo_step'] + key = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] + labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] + for i in range(0,6): + axes[i].semilogy(x, res[key[i]], label=plotName) + axes[i].set_ylabel(labels[i]) + + for i in range(0,6): + axes[i].legend() + axes[i].grid(which='major', color='gray') + axes[i].set_xlabel('Pseudo step'); + axes[i].set_yticks(10.0**np.arange(-14,-3)); + axes[i].set_ylim([1e-13,1e-3]) + axes[i].set_xlim([0,10000]) + return 0 + + + + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +naming = ["Wall Resolved", "Wall Modeled"] + +def main(): + + #Plot loads convergence histories + global figures, axes + figures = [] + axes = [] + for i in range(0,2): + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + dir_path= os.path.join(os.getcwd(),f'figures') + if not os.path.isdir(dir_path): # if directory already exists: + os.makedirs(dir_path) # make that dir + + j=0 + for resolution in caseNameList: + csvPath = os.path.join(os.getcwd(),f'{resolution}','surface_forces_v2.csv') + data = getDataDictFromCsv(csvPath) + computeCLCD(data) + plotLoads(data, resolution, naming[j]) + j=j+1 + + figures[0].savefig(f'figures/CL.png', dpi=500); + figures[1].savefig(f'figures/CD.png', dpi=500); + + for i in range(0,2): + axes[i].cla(); + + #Plot residual convergence histories + for i in range(0,6): + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + j=0 + for resolution in caseNameList: + csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') + res = getDataDictFromCsv(csvPath) + plotResiduals(res, resolution, naming[j]) + j=j+1 + figures[0].savefig(f'figures/Cont.png', dpi=500); + figures[1].savefig(f'figures/Momx.png', dpi=500); + figures[2].savefig(f'figures/Momy.png', dpi=500); + figures[3].savefig(f'figures/Momz.png', dpi=500); + figures[4].savefig(f'figures/Energy.png', dpi=500); + figures[5].savefig(f'figures/nuHat.png', dpi=500); + + + +if __name__ == '__main__': + main() + diff --git a/examples/Wall_Model/Download_Data.py b/examples/Wall_Model/Download_Data.py new file mode 100644 index 0000000..edce618 --- /dev/null +++ b/examples/Wall_Model/Download_Data.py @@ -0,0 +1,29 @@ +import os +import flow360 as fl +from flow360.component.case import CaseDownloadable +from flow360 import MyCases + +files = ["nonlinear_residual_v2.csv", "surface_forces_v2.csv", "total_forces_v2.csv"] + +downloadable =["NONLINEAR_RESIDUALS", "SURFACE_FORCES", "TOTAL_FORCES"] + +#read in caseNameList + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +my_cases = MyCases() + +for i in range(0, len(caseNameList)): + caseFolder = os.path.join(os.getcwd(), caseNameList[i]) + os.makedirs(caseFolder, exist_ok = True) + #Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == caseNameList[i]: + break + #Download the files + for j in range(0, len(files)): + dst = os.path.join(caseFolder, files[j]) + case.results.download_file(getattr(CaseDownloadable,downloadable[j]), to_file=dst) + #case.results.download_surface() + #case.results.download_volumetric() diff --git a/examples/Wall_Model/Files.py b/examples/Wall_Model/Files.py new file mode 100644 index 0000000..970a5ee --- /dev/null +++ b/examples/Wall_Model/Files.py @@ -0,0 +1,15 @@ +from flow360.examples.base_test_case import BaseTestCase + +class WallResolved(BaseTestCase): + name = "wall_resolved" + + class url: + mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Resolved_1e-06.b8.ugrid" + case_json = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/JSON/Flow360.json" + +class WallModel(BaseTestCase): + name = "wall_model" + + class url: + mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Model_5e-04.b8.ugrid" + diff --git a/examples/Wall_Model/README b/examples/Wall_Model/README new file mode 100644 index 0000000..be8ecec --- /dev/null +++ b/examples/Wall_Model/README @@ -0,0 +1,11 @@ +To run the demo case follow these steps: + +1. Run Submit_Cases.py -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. + +2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. + +3. Run Convergence_Plots.py -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. + +Files.py contains reference to the location of the meshes and JSON files + + diff --git a/examples/Wall_Model/Submit_Cases.py b/examples/Wall_Model/Submit_Cases.py new file mode 100644 index 0000000..3a62010 --- /dev/null +++ b/examples/Wall_Model/Submit_Cases.py @@ -0,0 +1,44 @@ +import flow360 as fl +from Files import WallResolved, WallModel + +print("Downloading mesh and solver files") + +WallResolved.get_files() +WallModel.get_files() + +print("Files downloaded") + +caseNameList=[] + +# submit wall resolved mesh +volume_mesh = fl.VolumeMesh.from_file(WallResolved.mesh_filename, name="Windsor_Wall_Resolved_Mesh") +volume_mesh = volume_mesh.submit() + + +# submit wall model mesh +volume_mesh2 = fl.VolumeMesh.from_file(WallModel.mesh_filename, name="Windsor_Wall_Modeled_Mesh") +volume_mesh2 = volume_mesh2.submit() + + # submit wall-resolved case using json file +params = fl.Flow360Params(WallResolved.case_json) +case = fl.Case.create("Windsor_Wall_Resolved", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +# Change noSlipWall to wallFunction in params + +Boundaries = params.boundaries +params.boundaries = Boundaries.copy(update={ "1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), "4": fl.WallFunction(name="Flow.CFDWT.Floor"), "8": fl.WallFunction(name="Windsor"), "9": fl.WallFunction(name="Windsor_rear"), "10": fl.WallFunction(name="Windsor_supports")}) + +# submit wall-modeled case using updated parameters + +case = fl.Case.create("Windsor_Wall_Modeled", params, volume_mesh2.id) +caseNameList.append(case.name) +case = case.submit() + +# dump case names for use in download and post-processing scripts + +with open('caseNameList.dat', 'w') as f: + for line in caseNameList: + f.write(f"{line}\n") + From 87191661775edd6012b498622153bdb15444dd2a Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Wed, 2 Aug 2023 17:32:29 +0100 Subject: [PATCH 02/14] Applied Comments from Maciej --- examples/Wall_Model/.Download_Data.py.swp | Bin 12288 -> 0 bytes examples/Wall_Model/Convergence_Plots.py | 93 +++++++++------------- examples/Wall_Model/Download_Data.py | 2 - examples/Wall_Model/{README => README.md} | 0 4 files changed, 39 insertions(+), 56 deletions(-) delete mode 100644 examples/Wall_Model/.Download_Data.py.swp rename examples/Wall_Model/{README => README.md} (100%) diff --git a/examples/Wall_Model/.Download_Data.py.swp b/examples/Wall_Model/.Download_Data.py.swp deleted file mode 100644 index 5f043c7f379fd12223c146189a1730441597902c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2&ubGw6vwAtwJLhhi!dgKB#>^?7OgD=8qx#`X(CChLa57hcam&7yAyUMjRAlB z3-vGXFX-RkpWwxd;>D|8^y0;fZ#LOxQ;SmYBD{fbcX#GH@4flV>>+gb3y-$8=>uzt zK)X)J(@$^R#`^Kx@E#$$Cw->Oz@OXLxA5d)Yhh`1VQqD(aK8WL*tl38C@p;++Kqt@ zIdgi8kC_nmwsg6$t6spw;-(x1LNeFhWSUw1(fI+f7YQJN3lNwmE6d}zGo89iZ{FCw zz+AK<0VIF~kN^@u0!RP}AOR%szZ1~?Ir0h?acQ!UJCp0&nd{^cFGv6hAOR$R1dsp{ zKmter2_OL^fCP}he@KA2gtRXc@)czM{~!PU|8b3w&!7{~YtS)h9kd4eewC1KppT#r zpcBvw&~s21)B$aP2LWEko+~+g`RWcs@>V9@+vhHp4w%nru^2tn;lAc6-S+mT@l6?~P*aINvdyiUj;7&*XE(|$nC7s=$U5|NFY1h< zJ2Hgr>dV0Of-V4>jzCD`kMo`u2$Xzw$Xzc~Gm!W*sLqy$0CFcB@F^=3WlZucV+aMi z=M3E}Y)EHX#T;=JD&Cv65biPsImw?}0|0M5>7wMjcT%nrf%WRTHPec@^01<{0v zitNKCW|C7Zm+4HNX2ML4G8IjSlxY*eRF}p$)s_xdSHbqh-rcM<&qZ zRj~n-!&PEHOAW@^ZWA_?KJ5rOT)AJMp5K?Dj*-obS&oFkfCt(#3yiI0xR1}Xd8f!E NL>$rZ5pkzf0 and (not key.isspace()): - data[key.strip()].append(float(value)) - return data +import pandas as pd def computeCLCD(data): CL0 = np.add(data['Windsor_CL'], data['Windsor_rear_CL']) @@ -22,35 +12,34 @@ def computeCLCD(data): -def plotLoads(data, caseName, plotName): - axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) - axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) - axes[0].set_ylabel('CL'); - axes[1].set_ylabel('CD'); - axes[0].set_ylim(-0.2, -0.1); - axes[1].set_ylim(0.25, 0.45); - - for i in range(0,2): - axes[i].legend() - axes[i].set_xlabel('Pseudo step'); - axes[i].grid(which='major', color='gray') - -def plotResiduals(res, caseName, plotName): +def plotLoads(data, plotName): + x = data['pseudo_step'] + keys = ['CL', 'CD'] + for ax, key in zip(axes, keys): + ax.plot(x, data[key], label = plotName) + ax.set_ylabel(key) + ax.legend() + ax.set_xlabel('Pseudo step'); + ax.grid(which='major', color='gray') + if (key == 'CL'): + ax.set_ylim(-0.2, -0.1) + elif (key == 'CD'): + ax.set_ylim(0.25, 0.45); + +def plotResiduals(res, plotName): x = res['pseudo_step'] - key = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] + keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] - for i in range(0,6): - axes[i].semilogy(x, res[key[i]], label=plotName) - axes[i].set_ylabel(labels[i]) + for ax, key, label in zip(axes, keys, labels): + ax.semilogy(x, res[key], label = plotName) + ax.set_ylabel(label) + ax.legend() + ax.grid(which='major', color='gray') + ax.set_xlabel('Pseudo step'); + ax.set_yticks(10.0**np.arange(-14,-3)); + ax.set_ylim([1e-13,1e-3]) + ax.set_xlim([0,10000]) - for i in range(0,6): - axes[i].legend() - axes[i].grid(which='major', color='gray') - axes[i].set_xlabel('Pseudo step'); - axes[i].set_yticks(10.0**np.arange(-14,-3)); - axes[i].set_ylim([1e-13,1e-3]) - axes[i].set_xlim([0,10000]) - return 0 @@ -59,46 +48,42 @@ def plotResiduals(res, caseName, plotName): caseNameList = file.read().splitlines() naming = ["Wall Resolved", "Wall Modeled"] +figures = [] +axes = [] def main(): #Plot loads convergence histories - global figures, axes - figures = [] - axes = [] - for i in range(0,2): + for i in [0,1]: fig, ax = plt.subplots(figsize=(8,6)) figures.append(fig) axes.append(ax) - dir_path= os.path.join(os.getcwd(),f'figures') + dir_path= os.path.join(os.getcwd(),f'figures') if not os.path.isdir(dir_path): # if directory already exists: os.makedirs(dir_path) # make that dir - j=0 - for resolution in caseNameList: + for j, resolution in enumerate(caseNameList): csvPath = os.path.join(os.getcwd(),f'{resolution}','surface_forces_v2.csv') - data = getDataDictFromCsv(csvPath) + data = pd.read_csv(csvPath, skipinitialspace=True) computeCLCD(data) - plotLoads(data, resolution, naming[j]) - j=j+1 + plotLoads(data, naming[j]) figures[0].savefig(f'figures/CL.png', dpi=500); figures[1].savefig(f'figures/CD.png', dpi=500); - for i in range(0,2): - axes[i].cla(); + for ax in axes: + ax.cla(); #Plot residual convergence histories for i in range(0,6): fig, ax = plt.subplots(figsize=(8,6)) figures.append(fig) axes.append(ax) - j=0 - for resolution in caseNameList: + for j, resolution in enumerate(caseNameList): csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') - res = getDataDictFromCsv(csvPath) - plotResiduals(res, resolution, naming[j]) - j=j+1 + res = pd.read_csv(csvPath, skipinitialspace=True) + plotResiduals(res, naming[j]) + figures[0].savefig(f'figures/Cont.png', dpi=500); figures[1].savefig(f'figures/Momx.png', dpi=500); figures[2].savefig(f'figures/Momy.png', dpi=500); diff --git a/examples/Wall_Model/Download_Data.py b/examples/Wall_Model/Download_Data.py index edce618..0aa5e29 100644 --- a/examples/Wall_Model/Download_Data.py +++ b/examples/Wall_Model/Download_Data.py @@ -25,5 +25,3 @@ for j in range(0, len(files)): dst = os.path.join(caseFolder, files[j]) case.results.download_file(getattr(CaseDownloadable,downloadable[j]), to_file=dst) - #case.results.download_surface() - #case.results.download_volumetric() diff --git a/examples/Wall_Model/README b/examples/Wall_Model/README.md similarity index 100% rename from examples/Wall_Model/README rename to examples/Wall_Model/README.md From d3f9ca11812230d8e0a19679a94cefe298eecf04 Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 15 Aug 2023 16:32:27 +0100 Subject: [PATCH 03/14] Customer_Outreach_Examples_Scripts --- README.md | 21 ++-- .../ONERAM6/Convergence_Plots_10.py | 91 +++++++++++++++ .../ONERAM6/Convergence_Plots_3p06.py | 92 +++++++++++++++ .../Adaptive_CFL/ONERAM6}/Download_Data.py | 8 +- .../Adaptive_CFL/ONERAM6/Files.py | 21 ++++ .../Adaptive_CFL/ONERAM6/README.md | 12 ++ .../Adaptive_CFL/ONERAM6/Submit_Cases.py | 59 ++++++++++ .../ONERAM6/localFiles/Flow360.json | 68 +++++++++++ .../Adaptive_CFL/XV15/ConvergencePlots.py | 78 +++++++++++++ .../Adaptive_CFL/XV15/Download_Data.py | 21 ++++ .../Adaptive_CFL/XV15/Files.py | 22 ++++ .../Adaptive_CFL/XV15/README.md | 12 ++ .../Adaptive_CFL/XV15/Submit_Cases.py | 63 +++++++++++ .../Adaptive_CFL/XV15/localFiles/Flow360.json | 106 ++++++++++++++++++ .../Debug_Divergence/Download_Data.py | 22 ++++ .../Solver_Features/Debug_Divergence/Files.py | 33 ++++++ .../Print_Divergence_Locations.py | 27 +++++ .../Solver_Features/Debug_Divergence/README | 25 +++++ .../Debug_Divergence/Submit_Cases.py | 37 ++++++ .../localFiles/.Flow360_AD.json.swp | Bin 0 -> 12288 bytes .../localFiles/Flow360_AD.json | 89 +++++++++++++++ .../localFiles/Flow360_PoorSurface.json | 76 +++++++++++++ .../Wall_Model/Convergence_Plots.py | 2 +- .../Wall_Model/Download_Data.py | 21 ++++ examples/Solver_Features/Wall_Model/Files.py | 31 +++++ .../Wall_Model/README.md | 4 +- .../Wall_Model/Submit_Cases.py | 6 +- .../Wall_Model/localFiles/Flow360.json | 88 +++++++++++++++ examples/Wall_Model/Files.py | 15 --- 29 files changed, 1110 insertions(+), 40 deletions(-) create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py rename examples/{Wall_Model => Solver_Features/Adaptive_CFL/ONERAM6}/Download_Data.py (58%) create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Files.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/README.md create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json create mode 100644 examples/Solver_Features/Debug_Divergence/Download_Data.py create mode 100644 examples/Solver_Features/Debug_Divergence/Files.py create mode 100644 examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py create mode 100644 examples/Solver_Features/Debug_Divergence/README create mode 100644 examples/Solver_Features/Debug_Divergence/Submit_Cases.py create mode 100644 examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp create mode 100644 examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json create mode 100644 examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json rename examples/{ => Solver_Features}/Wall_Model/Convergence_Plots.py (97%) create mode 100644 examples/Solver_Features/Wall_Model/Download_Data.py create mode 100644 examples/Solver_Features/Wall_Model/Files.py rename examples/{ => Solver_Features}/Wall_Model/README.md (69%) rename examples/{ => Solver_Features}/Wall_Model/Submit_Cases.py (94%) create mode 100644 examples/Solver_Features/Wall_Model/localFiles/Flow360.json delete mode 100644 examples/Wall_Model/Files.py diff --git a/README.md b/README.md index 98fe281..fcb2f9d 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,14 @@ -# Flow360Scripts +To run the demo case follow these steps: +1. Run Submit_Cases.py -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. -## BET Translators +2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. -See [`examples/BET/README.md`](examples/BET/README.md) +3. Run Convergence_Plots.py -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. +Files.py contains reference to the location of the meshes and JSON files. -# Developers +- The Flow360.json file is contained in the "Files" directory. +- The meshes are obtained by default from files stored on Flexcompute storage servers, or by setting an optional flag --localFiles to 1, locally stored files can be used from the "Files" directory. -Run tests: -```bash -cd tests -python -m unittest -``` - -deploy -``` -poetry lock -``` diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py new file mode 100644 index 0000000..f61b47e --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py @@ -0,0 +1,91 @@ +import matplotlib.pyplot as plt +from collections import defaultdict +import os, csv +import numpy as np +import pandas as pd + + + + +def plotLoads(data, plotName): + axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) + axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) + axes[0].set_ylabel('CL'); + axes[1].set_ylabel('CD'); + axes[0].set_ylim(0.45, 0.8); + axes[1].set_ylim(0.1, 0.15); + + for ax in axes: + ax.legend() + ax.set_xlabel('Pseudo step'); + ax.grid(which='major', color='gray') + +def plotResiduals(res, plotName): + x = res['pseudo_step'] + keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] + labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] + for ax, key, label in zip(axes, keys, labels): + for j, key in enumerate(keys): + if plotName =="Ramp": + ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) + else: + ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) + ax.set_ylabel('Residuals') + ax.legend() + ax.set_title("ONERAM6 10.0 deg") + ax.grid(which='major', color='gray') + ax.set_xlabel('Pseudo step'); + ax.set_yticks(10.0**np.arange(-14,-3)); + ax.set_ylim([1e-10,1e-3]) + ax.set_xlim([0,8000]) + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +naming = ["Ramp", "Adaptive", "Ramp", "Adaptive"] +figures = [] +axes = [] + +def main(): + + #Plot loads convergence histories + for i in [0,1]: + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + dir_path= os.path.join(os.getcwd(),f'figures') + if not os.path.isdir(dir_path): # if directory already exists: + os.makedirs(dir_path) # make that dir + + for j, resolution in enumerate(caseNameList): + if "10" in resolution: + csvPath = os.path.join(os.getcwd(),f'{resolution}', 'total_forces_v2.csv') + data = pd.read_csv(csvPath, skipinitialspace=True) + plotLoads(data, naming[j]) + + + figures[0].savefig(f'figures/CL_AoA10.png', dpi=500); + figures[1].savefig(f'figures/CD_AoA10.png', dpi=500); + + for i in range(0,2): + axes[i].cla(); + + #Plot residual convergence histories + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + for j, resolution in enumerate(caseNameList): + if "10" in resolution: + if "ADAPTIVE" in resolution: + figures[0].gca().set_prop_cycle(None) + csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') + res = pd.read_csv(csvPath, skipinitialspace=True) + plotResiduals(res, naming[j]) + + figures[0].savefig(f'figures/Residuals_AoA10.png', dpi=500); + + + +if __name__ == '__main__': + main() + diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py new file mode 100644 index 0000000..e8f3118 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py @@ -0,0 +1,92 @@ +import matplotlib.pyplot as plt +from collections import defaultdict +import os, csv +import numpy as np +import pandas as pd + + + + +def plotLoads(data, plotName): + axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) + axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) + axes[0].set_ylabel('CL'); + axes[1].set_ylabel('CD'); + axes[0].set_ylim(0.25, 0.3); + axes[1].set_ylim(0.0, 0.05); + + for ax in axes: + ax.legend() + ax.set_xlabel('Pseudo step'); + ax.grid(which='major', color='gray') + +def plotResiduals(res, plotName): + x = res['pseudo_step'] + keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] + labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] + for ax, key, label in zip(axes, keys, labels): + for j, key in enumerate(keys): + if plotName =="Ramp": + ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) + else: + ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) + ax.set_ylabel('Residuals') + ax.legend() + ax.set_title("ONERAM6 -3.06 deg") + ax.grid(which='major', color='gray') + ax.set_xlabel('Pseudo step'); + ax.set_yticks(10.0**np.arange(-14,-3)); + ax.set_ylim([1e-10,1e-3]) + ax.set_xlim([0,4000]) + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +naming = ["Ramp", "Adaptive"] +figures = [] +axes = [] + +def main(): + + #Plot loads convergence histories + for i in [0,1]: + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + dir_path= os.path.join(os.getcwd(),f'figures') + if not os.path.isdir(dir_path): # if directory already exists: + os.makedirs(dir_path) # make that dir + + for j, resolution in enumerate(caseNameList): + if "3p06" in resolution: + + csvPath = os.path.join(os.getcwd(),f'{resolution}','total_forces_v2.csv') + data = pd.read_csv(csvPath, skipinitialspace=True) + plotLoads(data, naming[j]) + + + figures[0].savefig(f'figures/CL_AoA3p06.png', dpi=500); + figures[1].savefig(f'figures/CD_AoA3p06.png', dpi=500); + + for i in range(0,2): + axes[i].cla(); + + #Plot residual convergence histories + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + for j, resolution in enumerate(caseNameList): + if "3p06" in resolution: + if "ADAPTIVE" in resolution: + figures[0].gca().set_prop_cycle(None) + csvPath = os.path.join(os.getcwd(),f'{resolution}', 'nonlinear_residual_v2.csv') + res = pd.read_csv(csvPath, skipinitialspace=True) + plotResiduals(res, naming[j]) + + figures[0].savefig(f'figures/Residuals_AoA3p06.png', dpi=500); + + + +if __name__ == '__main__': + main() + diff --git a/examples/Wall_Model/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py similarity index 58% rename from examples/Wall_Model/Download_Data.py rename to examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py index 0aa5e29..abb056c 100644 --- a/examples/Wall_Model/Download_Data.py +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py @@ -1,11 +1,7 @@ import os import flow360 as fl -from flow360.component.case import CaseDownloadable from flow360 import MyCases -files = ["nonlinear_residual_v2.csv", "surface_forces_v2.csv", "total_forces_v2.csv"] - -downloadable =["NONLINEAR_RESIDUALS", "SURFACE_FORCES", "TOTAL_FORCES"] #read in caseNameList @@ -22,6 +18,4 @@ if case.name == caseNameList[i]: break #Download the files - for j in range(0, len(files)): - dst = os.path.join(caseFolder, files[j]) - case.results.download_file(getattr(CaseDownloadable,downloadable[j]), to_file=dst) + case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py new file mode 100644 index 0000000..c190f8f --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py @@ -0,0 +1,21 @@ +import os +from flow360.examples import base_test_case +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--localFiles', default = 0, type = int, required = False) +args = parser.parse_args() +local = args.localFiles + +base_test_case.here = os.path.dirname(os.path.abspath(__file__)) + +class ONERAM6(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://mesh.lb8.ugrid" + case_json = "local://Flow360.json" + else: + class url: + mesh = "PLACEHOLDER" + case_json = "PLACEHOLDER" diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md b/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md new file mode 100644 index 0000000..e823088 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md @@ -0,0 +1,12 @@ +To run the demo case follow these steps: + +1. Run Submit_Cases.py -> this script will obtain the mesh and submit ramp and adaptive CFL cases for the ONERAM6 wing at two angles of attack + +2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. + +3. Run Convergence_Plots_3p06.py and Convergence_Plots_10.py -> these script will cross-plot the load and residual convergence histories for the ramp and adaptive CFL cases at two angles of attack. + +Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". +To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 + + diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py new file mode 100644 index 0000000..c74366d --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py @@ -0,0 +1,59 @@ +import os +import flow360 as fl +from Files import ONERAM6 + +print("Obtaining mesh and solver files") + +ONERAM6.get_files() + +print("Files accessed") + +caseNameList=[] + +# submit mesh +volume_mesh = fl.VolumeMesh.from_file(ONERAM6.mesh_filename, name="ONERAM6_Mesh") +volume_mesh = volume_mesh.submit() + + +params = fl.Flow360Params(ONERAM6.case_json) + +#submit ramp CFL case at alpha = 3.06 +case = fl.Case.create("ONERAM6_3p06_RAMP", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +#change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +#submit adaptive CFL case at alpha = 3.06 +case = fl.Case.create("ONERAM6_3p06_ADAPTIVE", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +#change CFL type to ramp, modify time stepping settings and increase alpha to 10 +params.time_stepping.CFL.type = "ramp" +params.time_stepping.max_pseudo_steps = 8000 +params.time_stepping.CFL.initial = 1 +params.time_stepping.CFL.final = 20 +params.time_stepping.CFL.ramp_steps = 200 +params.freestream.alpha = 10 + +#submit ramp CFL case at alpha = 10 +case = fl.Case.create("ONERAM6_10_RAMP", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + + +#change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +#submit adaptive CFL case at alpha = 10 +case = fl.Case.create("ONERAM6_10_ADAPTIVE", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +# dump case names for use in download and post-processing scripts + +with open('caseNameList.dat', 'w') as f: + for line in caseNameList: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json b/examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json new file mode 100644 index 0000000..b2c1afd --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json @@ -0,0 +1,68 @@ +{ + "geometry": { + "meshName": "wing_mixed_ph.2.lb8.ugrid", + "endianness": "little", + "refArea": 1.15315084119231, + "momentCenter": [ + 0, + 0, + 0 + ], + "momentLength": [ + 0.801672958512342, + 0.801672958512342, + 0.801672958512342 + ] + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields": ["primitiveVars", "Mach", "qcriterion"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields": ["primitiveVars", "Cp", "Cf", "CfVec", "yPlus"] + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-10, + "linearIterations": 25, + "kappaMUSCL": -1, + "limitVelocity": false, + "limitPressureDensity": false + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "absoluteTolerance": 1e-10, + "linearIterations": 20, + "kappaMUSCL": -1, + "rotationCorrection": false + }, + "freestream": { + "Reynolds": 14600000, + "Mach": 0.84, + "Temperature": 288.15, + "alphaAngle": 3.06, + "betaAngle": 0 + }, + "timeStepping": { + "timeStepSize": "inf", + "physicalSteps": 1, + "maxPseudoSteps": 4000, + "CFL": { + "initial": 10, + "final": 100, + "rampSteps": 200, + "type": "ramp" + } + }, + "boundaries": { + "1": { + "type": "NoSlipWall" + }, + "2": { + "type": "SlipWall" + }, + "3": { + "type": "Freestream" + } + } +} diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py b/examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py new file mode 100644 index 0000000..5a3a540 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py @@ -0,0 +1,78 @@ +import matplotlib.pyplot as plt +from collections import defaultdict +import os, csv, json +import numpy as np +import pandas as pd + +def addAccumPseudoStep(history): + pseudoSteps = history['pseudo_step'] + accum = list() + accum.append(0) + for i in range(1,len(pseudoSteps)): + if pseudoSteps[i] > pseudoSteps[i-1]: + accum.append(accum[-1]+abs(pseudoSteps[i] - pseudoSteps[i-1])) + else: + accum.append(accum[-1]+1) + history['accum_pseudo_step'] = accum + + +def plotResiduals(res, caseName, plotName): + x = res['accum_pseudo_step'] + keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] + labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] + for ax, key, label in zip(axes, keys, labels): + for j, key in enumerate(keys): + if plotName =="Ramp": + ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) + else: + ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) + ax.legend(loc='upper right') + ax.grid(which='major', color='gray') + + ax.set_title("XV15 Rotor - Residuals") + ax.set_xlabel('Accumulated Pseudo step'); + ax.set_yticks(10.0**np.arange(-11,-3)); + ax.set_ylim([1e-9,1e-3]) + ax.set_xlim([3000,4000]) + ax.set_ylabel('Residuals') + + +caseNameList = ["XV15_2nd_order_ramp_forked", "XV15_2nd_order_adaptive_forked"] +naming= ["Ramp", "Adaptive"] +figures = [] +axes = [] + +def main(): + fig, ax = plt.subplots(figsize=(8,6)) + figures.append(fig) + axes.append(ax) + dir_path= os.path.join(os.getcwd(),f'figures') + if not os.path.isdir(dir_path): # if directory already exists: + os.makedirs(dir_path) # make that dir + + for j, resolution in enumerate(caseNameList): + csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') + res = pd.read_csv(csvPath, skipinitialspace=True) + addAccumPseudoStep(res) + plotResiduals(res, resolution, naming[j]) + figures[0].gca().set_prop_cycle(None) + figures[0].savefig(f'figures/Residuals.png', dpi=500); + axes[0].set_xlim([3450,3550]) + figures[0].savefig(f'figures/ResidualsZoomed.png', dpi=500); + + caseNameList2 = ["XV15_2nd_order_adaptive"] + naming2= ["Adaptive"] + for ax in axes: + ax.cla(); + + for j, resolution in enumerate(caseNameList2): + csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') + res = pd.read_csv(csvPath, skipinitialspace=True) + addAccumPseudoStep(res) + plotResiduals(res, resolution, naming2[j]) + axes[0].set_xlim([0,4000]) + figures[0].savefig(f'figures/Residuals_Adaptive_from_scratch.png', dpi=500); + +if __name__ == '__main__': + main() + diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py new file mode 100644 index 0000000..abb056c --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py @@ -0,0 +1,21 @@ +import os +import flow360 as fl +from flow360 import MyCases + + +#read in caseNameList + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +my_cases = MyCases() + +for i in range(0, len(caseNameList)): + caseFolder = os.path.join(os.getcwd(), caseNameList[i]) + os.makedirs(caseFolder, exist_ok = True) + #Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == caseNameList[i]: + break + #Download the files + case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Files.py b/examples/Solver_Features/Adaptive_CFL/XV15/Files.py new file mode 100644 index 0000000..75c6034 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Files.py @@ -0,0 +1,22 @@ +import os +from flow360.examples import base_test_case +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--localFiles', default = 0, type = int, required = False) +args = parser.parse_args() +local = args.localFiles + +base_test_case.here = os.path.dirname(os.path.abspath(__file__)) + +class XV15(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://xv15_airplane_pitch26.cgns" + case_json = "local://Flow360.json" + else: + class url: + mesh = "PLACEHOLDER" + case_json = "PLACEHOLDER" + diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/README.md b/examples/Solver_Features/Adaptive_CFL/XV15/README.md new file mode 100644 index 0000000..a9943b4 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/README.md @@ -0,0 +1,12 @@ +To run the demo case follow these steps: + +1. Run Submit_Cases.py -> this script will obtain the mesh and submit ramp and adaptive CFL cases for the XV15 rotor. + +2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. + +3. Run Convergence_Plots.py -> this script will cross-plot the residual convergence histories for the ramp and adaptive CFL cases forked from the 1st order solution and a clean 2nd order adpative CFL simulation. + +Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". +To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 + + diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py b/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py new file mode 100644 index 0000000..29ee8dc --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py @@ -0,0 +1,63 @@ +import flow360 as fl +from Files import XV15 + +print("Obtaining mesh and solver files") + +XV15.get_files() + +print("Files accessed") + +caseNameList=[] + +# submit mesh +volume_mesh = fl.VolumeMesh.from_file(XV15.mesh_filename, name="XV15_Mesh") +volume_mesh = volume_mesh.submit() + +#submit 1st order case +params = fl.Flow360Params(XV15.case_json) +case = fl.Case.create("XV15_1st_order_ramp", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +#update solver and time-stepping parameters +params.navier_stokes_solver.order_of_accuracy=2 +params.turbulence_model_solver.order_of_accuracy=2 + +params.time_stepping.max_pseudo_steps = 35 +params.time_stepping.time_step_size = 29.08882086657216 + +params.time_stepping.CFL.final = 1e7 +params.time_stepping.CFL.ramp_steps = 33 + + +#submit 2nd order ramp case (forked from first order) +case_fork_1 = case.fork() +case_fork_1.name = "XV15_2nd_order_ramp_forked" +caseNameList.append(case_fork_1.name) +case_fork_1.params = params +print(params) +case_fork_1 = case_fork_1.submit() + +#change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +#submit 2nd order adaptive case (forked from first order) +case_fork_2 = case.fork() +case_fork_2.name = "XV15_2nd_order_adaptive_forked" +caseNameList.append(case_fork_2.name) +case_fork_2.params = params +print(params) +case_fork_2 = case_fork_2.submit() + + +#submit adaptive CFL case +case = fl.Case.create("XV15_2nd_order_adaptive", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + + +# dump case names for use in download and post-processing scripts + +with open('caseNameList.dat', 'w') as f: + for line in caseNameList: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json b/examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json new file mode 100644 index 0000000..09752ab --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json @@ -0,0 +1,106 @@ +{ + "geometry": { + "refArea": 70685.83470577035, + "momentCenter": [ + 0, + 0, + 0 + ], + "momentLength": [ + 150, + 150, + 150 + ] + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields" : ["primitiveVars", "qcriterion", "Mach"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields" : ["primitiveVars", "Cp", "Cf", "CfVec", "yPlus"] + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-9, + "relativeTolerance": 0.01, + "linearIterations": 35, + "kappaMUSCL": -1, + "orderOfAccuracy": 1, + "updateJacobianFrequency": 1, + "equationEvalFrequency": 1 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "absoluteTolerance": 1e-8, + "relativeTolerance": 0.01, + "linearIterations": 35, + "DDES": true, + "orderOfAccuracy": 1, + "updateJacobianFrequency": 1, + "equationEvalFrequency": 1, + "rotationCorrection": true + }, + "freestream": { + "muRef": 0.00000168, + "Mach": 0.182, + "MachRef": 0.54, + "Temperature": 288.15, + "alphaAngle": -90, + "betaAngle": 0 + }, + "boundaries": { + "stationaryField/farfield": { + "type": "Freestream" + }, + "stationaryField/rotationInterface_static": { + "type": "SlidingInterface" + }, + "rotationField/rotBnd": { + "type": "SlidingInterface" + }, + "rotationField/blade": { + "type": "NoSlipWall" + }, + "rotationField/blade_2": { + "type": "NoSlipWall" + }, + "rotationField/blade_3": { + "type": "NoSlipWall" + } + }, + "slidingInterfaces": [ + { + "stationaryPatches": [ + "stationaryField/rotationInterface_static" + ], + "rotatingPatches": [ + "rotationField/rotBnd" + ], + "axisOfRotation": [ + 0, + 0, + -1 + ], + "centerOfRotation": [ + 0, + 0, + 0 + ], + "omega": 0.0036, + "volumeName": [ + "rotationField" + ] + } + ], + "timeStepping": { + "timeStepSize": 29.08882086657216, + "physicalSteps": 120, + "maxPseudoSteps": 13, + "CFL": { + "type": "ramp", + "initial": 1, + "final": 1000, + "rampSteps": 11 + } + } +} diff --git a/examples/Solver_Features/Debug_Divergence/Download_Data.py b/examples/Solver_Features/Debug_Divergence/Download_Data.py new file mode 100644 index 0000000..c527847 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/Download_Data.py @@ -0,0 +1,22 @@ +import os +import flow360 as fl +from flow360 import MyCases + + +#read in caseNameList + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +my_cases = MyCases() + +for i in range(0, len(caseNameList)): + caseFolder = os.path.join(os.getcwd(), caseNameList[i]) + os.makedirs(caseFolder, exist_ok = True) + #Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == caseNameList[i]: + break + #Download the files + case.results.download(minmax_state=True, destination=caseFolder) + diff --git a/examples/Solver_Features/Debug_Divergence/Files.py b/examples/Solver_Features/Debug_Divergence/Files.py new file mode 100644 index 0000000..0d468a6 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/Files.py @@ -0,0 +1,33 @@ +import os +from flow360.examples import base_test_case +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--localFiles', default = 0, type = int, required = False) +args = parser.parse_args() +local = args.localFiles + +base_test_case.here = os.path.dirname(os.path.abspath(__file__)) + +class CRM_PoorSurface(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://Unswept_CRM_Poor_Surface.cgns" + case_json = "local://Flow360_PoorSurface.json" + else: + class url: + mesh = "PLACEHOLDER" + case_json = "PLACEHOLDER" + +class CRM_AD(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://Unswept_CRM_AD.cgns" + case_json = "local://Flow360_AD.json" + else: + class url: + mesh = "PLACEHOLDER" + case_json = "PLACEHOLDER" + diff --git a/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py b/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py new file mode 100644 index 0000000..873f80a --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py @@ -0,0 +1,27 @@ +import matplotlib.pyplot as plt +from collections import defaultdict +import os, csv +import numpy as np +import pandas as pd + + + + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +for resolution in caseNameList: + csvPath = os.path.join(os.getcwd(),f'{resolution}','minmax_state_v2.csv') + data = pd.read_csv(csvPath, skipinitialspace=True) + print(resolution) + print("Minimum Density: " + str(data[f"min_rho"][len(data)-1])+" at location (x="+ str(data[f"min_rho_x"][len(data)-1])+ ", y=" + str(data[f"min_rho_y"][len(data)-1])+", z="+ str(data[f"min_rho_z"][len(data)-1]) +")" ) + print("Minimum Pressure: " + str(data[f"min_p"][len(data)-1])+" at location (x="+ str(data[f"min_p_x"][len(data)-1])+ ", y=" + str(data[f"min_p_y"][len(data)-1])+", z="+ str(data[f"min_p_z"][len(data)-1]) +")" ) + print("Maximum Velocity Magnitude: " + str(data[f"max_umag"][len(data)-1])+" at location (x="+ str(data[f"max_umag_x"][len(data)-1])+ ", y=" + str(data[f"max_umag_y"][len(data)-1])+", z="+ str(data[f"max_umag_z"][len(data)-1]) +")" ) + print("Minimum nuHat Magnitude: " + str(data[f"min_nuHat"][len(data)-1])+" at location (x="+ str(data[f"min_nuHat_x"][len(data)-1])+ ", y=" + str(data[f"min_nuHat_y"][len(data)-1])+", z="+ str(data[f"min_nuHat_z"][len(data)-1]) +")" ) + + + + + + + diff --git a/examples/Solver_Features/Debug_Divergence/README b/examples/Solver_Features/Debug_Divergence/README new file mode 100644 index 0000000..e6413c1 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/README @@ -0,0 +1,25 @@ +The following cases are for a demonstration of the debug divergence pipeline and are intended to diverge. + +1. Run Submit_Cases.py -> this script will obtain the meshes, and upload them to the Flexcompute servers. The cases will also be submitted. + +2. Run Download_Data.py -> this script will download the csv files containing the min/max locations of the pressure, density, velocity magnitude and turbulent variables. + +3. Run Print_Divergence_Locations.py -> this script will print the minimum pressure, minimum density, maxiumum velocity magnitude and minimum nuHat at the last iteration. + +4. Investigate the mesh at the location, where one of the variables went non-physical (e.g. negative pressure or density) + +The debug divergence pipeline can also be used on the WebUI: + +1. Go to min/max tab and position cursor on last pseudo-step in plot. Read which variable diverged from plot or from table below. + +2. Go to case visualization tab. + +3. Turn-off all boundaries and slices + +4. Switch on non-slip walls. + +5. Switch on slices of interest for the diverged variable. + +6. Investigated multiple slices and views (flat vs crinkle vs wireframe with contour on/off) + +7. Examine the mesh for quality issues such as large jumps in area/volume ratio's diff --git a/examples/Solver_Features/Debug_Divergence/Submit_Cases.py b/examples/Solver_Features/Debug_Divergence/Submit_Cases.py new file mode 100644 index 0000000..05394b6 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/Submit_Cases.py @@ -0,0 +1,37 @@ +import flow360 as fl +from Files import CRM_PoorSurface, CRM_AD + +print("Obtaining mesh and solver files") + +CRM_PoorSurface.get_files() +CRM_AD.get_files() + +print("Files accessed") + +caseNameList=[] + +# submit mesh with poor surface +volume_mesh = fl.VolumeMesh.from_file(CRM_PoorSurface.mesh_filename, name="CRM_Poor_Surface_Mesh") +volume_mesh = volume_mesh.submit() + +#submit case with poor surface +params = fl.Flow360Params(CRM_PoorSurface.case_json) +case = fl.Case.create("CRM_Poor_Surface", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +# submit mesh with actuator disk +volume_mesh = fl.VolumeMesh.from_file(CRM_AD.mesh_filename, name="CRM_AD_Mesh") +volume_mesh = volume_mesh.submit() + +#submit case with actuator disk +params = fl.Flow360Params(CRM_AD.case_json) +case = fl.Case.create("CRM_AD", params, volume_mesh.id) +caseNameList.append(case.name) +case = case.submit() + +# dump case names for use in download and post-processing scripts + +with open('caseNameList.dat', 'w') as f: + for line in caseNameList: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp b/examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp new file mode 100644 index 0000000000000000000000000000000000000000..7807a00d9c246bbab77517d737947effb911a309 GIT binary patch literal 12288 zcmeI2&x;&I6vt~t!Hy55?wNY8 z-h1_}u7YK2;GS4ssdXA2!Sx^^XU_jHytsK`>hi-=M2*v!<=SxPtMsd%Jl?B&?fQJ% zb9eWDxpbWA7P(4eF4vD0N^%yA*ZWWQ`pZWT&n)smF6|f3e z1*`&A0jt3OPXU!pkykLRyQ-m`s-9DSdsbiV!zy4EunJfOtO8a6tAJI&Dqt0`3RnfK z0#yN63%h8}K>!0BnOLK*2p=3jDs8kYB*};0y2>_y}ACZ-E?~2B*L(cmg~I z4uC!2xBChC349B#f=|E|@E&*#gy0D1fP>%wm;%@CLtWrQ@Fpn0^Wa%<7(5QH?;+%8 z@E!ORoCmK12~w~Djsh1P0C$6H(Df_uKDZ1nfp>w{`)yz^tAJI&Dqt0`3RnfK0))Io zoYTa?9ls6@gba!}!u!tU7tGf-?^`>j)*_^Jq@OG#gOPs2N*=_h}YqYdsn$)Vx zp^^|fhY$QBKM|5dUqlujpd4H0v?ls(L z6r|CSP%sMRQrD?XHQ!WH84+ALKimMn$|^IyvO>Shx@bg=E1ND)IGTH&~XjmDOJN2wLi% z5g-x?XL1=SnL<)6g5NS0HpmfP@qQY?h=Z{(dA!~+Mwu$(-%X|Df$j-w$fBGZbDR!& z)ZfZh+Bmekq$dbcI5cMGj_14>rjx)e1U3Rz1!f`{mCmLLy?$?m z>_sAbhDDJnJ&X!5oXNN1m@6rQDnnKKq=+TSd9Dvg$2au}nGE#`*}corbeA-nJ7v*9 zS|mdz1=o5_=C`af=J|LPdMqa^+$>3to^Wm|u zr&HYG)ttq?G(YRQt&ZFAJ-?&35~wreNiNjZQzL}z76TDXl6wumeD^WW68ldf%{%XU zO}~ZxZyrC*cKK!nDP&AkH6(`)xMB;*DAFBFZIngXc&DjcG<_atdYzSV{SHpRm(k4P z*PC6Z{2mui^H4`ZR$Sg(XMTRJ<2UEL*>)QO=@;OJJaC-Is<$Y|GdDBVa*fA0_@1aE zJQ=AmoY!DKZOqW8rJeP2r$K+9WtVQXubM7Y^03^bYsR^Hb0%|$z<9T@iRtctm4}Wv NDo|2yMB8MW{0WS4Au|8~ literal 0 HcmV?d00001 diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json b/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json new file mode 100644 index 0000000..0a174a5 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json @@ -0,0 +1,89 @@ +{ + "geometry": { + "comments": { + "meshUnit": "inch" + }, + "refArea": 5, + "momentCenter": [ + 0.25, + 0.25, + 0.25 + ], + "momentLength": [ + 1, + 1, + 1 + ] + }, + "freestream": { + "muRef": 0.0000016899682361477025, + "Mach": 0.85, + "Temperature": 288.15, + "alphaAngle": 8, + "betaAngle": 0, + "comments": { + "pressure": 101325.009090375, + "densityKgPerCubicMeter": 1.225, + "speedOfSoundMeterPerSecond": 340.29400580821283, + "freestreamMeterPerSecond": 270, + "meshUnitInMeter": 0.0254 + } + }, + "boundaries": { + "fluid/wing": { + "type": "NoSlipWall" + }, + "fluid/farfield": { + "type": "Freestream" + }, + "fluid/symmetric": { + "type": "SlipWall" + } + }, + "timeStepping": { + "maxPseudoSteps": 5000, + "CFL": { + "type": "ramp", + "initial": 1, + "final": 200, + "rampSteps": 1000 + }, + "physicalSteps": 1, + "timeStepSize": "inf" + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-9, + "linearIterations": 35, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "rotationCorrection": false, + "absoluteTolerance": 1e-8, + "linearIterations": 25, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields": ["primitiveVars", "Mach", "qcriterion"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields": ["Cp", "Cf", "CfVec", "yPlus"] + }, + "actuatorDisks": + [ + { + "center":[-1.0, 2.5, 0.0], + "axisThrust":[-1.0,0.0,0.0], + "thickness": 0.3, + "forcePerArea":{ + "radius":[0.01, 0.7, 0.75], + "thrust":[0.2, 0.5, 0], + "circumferential":[-0.001, -0.003, 0] + } + } + ] +} diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json b/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json new file mode 100644 index 0000000..7ee57a5 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json @@ -0,0 +1,76 @@ +{ + "geometry": { + "comments": { + "meshUnit": "inch" + }, + "refArea": 5, + "momentCenter": [ + 0.25, + 0.25, + 0.25 + ], + "momentLength": [ + 1, + 1, + 1 + ] + }, + "freestream": { + "muRef": 0.0000016899682361477025, + "Mach": 0.85, + "Temperature": 288.15, + "alphaAngle": 8, + "betaAngle": 0, + "comments": { + "pressure": 101325.009090375, + "densityKgPerCubicMeter": 1.225, + "speedOfSoundMeterPerSecond": 340.29400580821283, + "freestreamMeterPerSecond": 270, + "meshUnitInMeter": 0.0254 + } + }, + "boundaries": { + "fluid/wing": { + "type": "NoSlipWall" + }, + "fluid/farfield": { + "type": "Freestream" + }, + "fluid/symmetric": { + "type": "SlipWall" + } + }, + "timeStepping": { + "maxPseudoSteps": 5000, + "CFL": { + "type": "ramp", + "initial": 1, + "final": 200, + "rampSteps": 1000 + }, + "physicalSteps": 1, + "timeStepSize": "inf" + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-9, + "linearIterations": 35, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "rotationCorrection": false, + "absoluteTolerance": 1e-8, + "linearIterations": 25, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields": ["primitiveVars", "Mach", "qcriterion"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields": ["Cp", "Cf", "CfVec", "yPlus"] + } +} diff --git a/examples/Wall_Model/Convergence_Plots.py b/examples/Solver_Features/Wall_Model/Convergence_Plots.py similarity index 97% rename from examples/Wall_Model/Convergence_Plots.py rename to examples/Solver_Features/Wall_Model/Convergence_Plots.py index 140a2e0..d43817e 100644 --- a/examples/Wall_Model/Convergence_Plots.py +++ b/examples/Solver_Features/Wall_Model/Convergence_Plots.py @@ -80,7 +80,7 @@ def main(): figures.append(fig) axes.append(ax) for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') + csvPath = os.path.join(os.getcwd(),f'{resolution}', 'nonlinear_residual_v2.csv') res = pd.read_csv(csvPath, skipinitialspace=True) plotResiduals(res, naming[j]) diff --git a/examples/Solver_Features/Wall_Model/Download_Data.py b/examples/Solver_Features/Wall_Model/Download_Data.py new file mode 100644 index 0000000..abb056c --- /dev/null +++ b/examples/Solver_Features/Wall_Model/Download_Data.py @@ -0,0 +1,21 @@ +import os +import flow360 as fl +from flow360 import MyCases + + +#read in caseNameList + +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +my_cases = MyCases() + +for i in range(0, len(caseNameList)): + caseFolder = os.path.join(os.getcwd(), caseNameList[i]) + os.makedirs(caseFolder, exist_ok = True) + #Find the latest case with the name corresponding to the name in caseNameList + for case in my_cases: + if case.name == caseNameList[i]: + break + #Download the files + case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Wall_Model/Files.py b/examples/Solver_Features/Wall_Model/Files.py new file mode 100644 index 0000000..e4a2491 --- /dev/null +++ b/examples/Solver_Features/Wall_Model/Files.py @@ -0,0 +1,31 @@ +import os +from flow360.examples import base_test_case +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--localFiles', default = 0, type = int, required = False) +args = parser.parse_args() +local = args.localFiles + +base_test_case.here = os.path.dirname(os.path.abspath(__file__)) + +class WallResolved(base_test_case.BaseTestCase): + name = "localFiles" + + if local ==1: + class url: + mesh = "local://Windsor_Wall_Resolved_1e-06.b8.ugrid" + case_json = "local://Flow360.json" + else: + class url: + mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Resolved_1e-06.b8.ugrid" + case_json = "local://Flow360.json" + +class WallModel(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://Windsor_Wall_Model_5e-04.b8.ugrid" + else: + class url: + mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Model_5e-04.b8.ugrid" diff --git a/examples/Wall_Model/README.md b/examples/Solver_Features/Wall_Model/README.md similarity index 69% rename from examples/Wall_Model/README.md rename to examples/Solver_Features/Wall_Model/README.md index be8ecec..de9aaa0 100644 --- a/examples/Wall_Model/README.md +++ b/examples/Solver_Features/Wall_Model/README.md @@ -6,6 +6,8 @@ To run the demo case follow these steps: 3. Run Convergence_Plots.py -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. -Files.py contains reference to the location of the meshes and JSON files +Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". +To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 + diff --git a/examples/Wall_Model/Submit_Cases.py b/examples/Solver_Features/Wall_Model/Submit_Cases.py similarity index 94% rename from examples/Wall_Model/Submit_Cases.py rename to examples/Solver_Features/Wall_Model/Submit_Cases.py index 3a62010..0072c25 100644 --- a/examples/Wall_Model/Submit_Cases.py +++ b/examples/Solver_Features/Wall_Model/Submit_Cases.py @@ -1,12 +1,14 @@ +import os import flow360 as fl from Files import WallResolved, WallModel -print("Downloading mesh and solver files") +print("Obtaining mesh and solver files") + WallResolved.get_files() WallModel.get_files() -print("Files downloaded") +print("Files accessed") caseNameList=[] diff --git a/examples/Solver_Features/Wall_Model/localFiles/Flow360.json b/examples/Solver_Features/Wall_Model/localFiles/Flow360.json new file mode 100644 index 0000000..7b32fc5 --- /dev/null +++ b/examples/Solver_Features/Wall_Model/localFiles/Flow360.json @@ -0,0 +1,88 @@ +{ + "geometry" : { + "refArea" : 0.056, + "momentCenter" : [0, 0, 0], + "momentLength" : [0.6375, 0.6375, 0.6375] + }, + "volumeOutput" : { + "outputFormat" : "paraview", + "outputFields" : ["primitiveVars", "qcriterion", "Mach"] + }, + "surfaceOutput" : { + "outputFormat" : "paraview", + "outputFields" : ["primitiveVars", "Cp", "Cf", "CfVec", "yPlus"] + }, + "navierStokesSolver" : { + "absoluteTolerance" : 1e-12, + "kappaMUSCL" : -1.0 + }, + "turbulenceModelSolver" : { + "modelType" : "SpalartAllmaras", + "absoluteTolerance" : 1e-10 + }, + "freestream": { + "muRef": 4.2925193198151646e-8, + "Mach": 0.11754541460405184, + "Temperature": 288.15, + "alphaAngle": 0, + "betaAngle": 0, + "comments": { + "pressure": 101325.009090375, + "densityKgPerCubicMeter": 1.225, + "speedOfSoundMeterPerSecond": 340.29400580821283, + "freestreamMeterPerSecond": 40, + "meshUnitInMeter": 1 + } + }, + "boundaries" : { + "1": { + "type": "NoSlipWall", + "name": "Flow.CFDWT.FloorUnder" + }, + "2": { + "type": "Freestream", + "name": "Flow.CFDWT.In" + }, + "3": { + "type": "SlipWall", + "name": "Flow.CFDWT.Left" + }, + "4": { + "type": "NoSlipWall", + "name": "Flow.CFDWT.Floor" + }, + "5": { + "type": "SlipWall", + "name": "Flow.CFDWT.Roof" + }, + "6": { + "type": "Freestream", + "name": "Flow.CFDWT.Out" + }, + "7": { + "type": "SlipWall", + "name": "symmetry" + }, + "8": { + "type": "NoSlipWall", + "name": "Windsor" + }, + "9": { + "type": "NoSlipWall", + "name": "Windsor_rear" + }, + "10": { + "type": "NoSlipWall", + "name": "Windsor_supports" + } + }, + "timeStepping" : { + "maxPseudoSteps" : 10000, + "CFL" : { + "type": "ramp", + "initial" : 1, + "final": 200, + "rampSteps" : 2000 + } + } +} diff --git a/examples/Wall_Model/Files.py b/examples/Wall_Model/Files.py deleted file mode 100644 index 970a5ee..0000000 --- a/examples/Wall_Model/Files.py +++ /dev/null @@ -1,15 +0,0 @@ -from flow360.examples.base_test_case import BaseTestCase - -class WallResolved(BaseTestCase): - name = "wall_resolved" - - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Resolved_1e-06.b8.ugrid" - case_json = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/JSON/Flow360.json" - -class WallModel(BaseTestCase): - name = "wall_model" - - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Model_5e-04.b8.ugrid" - From 239fd590d05652398718475418c665d876d72055 Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 15 Aug 2023 16:40:10 +0100 Subject: [PATCH 04/14] Removed swp file --- .../localFiles/.Flow360_AD.json.swp | Bin 12288 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp b/examples/Solver_Features/Debug_Divergence/localFiles/.Flow360_AD.json.swp deleted file mode 100644 index 7807a00d9c246bbab77517d737947effb911a309..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2&x;&I6vt~t!Hy55?wNY8 z-h1_}u7YK2;GS4ssdXA2!Sx^^XU_jHytsK`>hi-=M2*v!<=SxPtMsd%Jl?B&?fQJ% zb9eWDxpbWA7P(4eF4vD0N^%yA*ZWWQ`pZWT&n)smF6|f3e z1*`&A0jt3OPXU!pkykLRyQ-m`s-9DSdsbiV!zy4EunJfOtO8a6tAJI&Dqt0`3RnfK z0#yN63%h8}K>!0BnOLK*2p=3jDs8kYB*};0y2>_y}ACZ-E?~2B*L(cmg~I z4uC!2xBChC349B#f=|E|@E&*#gy0D1fP>%wm;%@CLtWrQ@Fpn0^Wa%<7(5QH?;+%8 z@E!ORoCmK12~w~Djsh1P0C$6H(Df_uKDZ1nfp>w{`)yz^tAJI&Dqt0`3RnfK0))Io zoYTa?9ls6@gba!}!u!tU7tGf-?^`>j)*_^Jq@OG#gOPs2N*=_h}YqYdsn$)Vx zp^^|fhY$QBKM|5dUqlujpd4H0v?ls(L z6r|CSP%sMRQrD?XHQ!WH84+ALKimMn$|^IyvO>Shx@bg=E1ND)IGTH&~XjmDOJN2wLi% z5g-x?XL1=SnL<)6g5NS0HpmfP@qQY?h=Z{(dA!~+Mwu$(-%X|Df$j-w$fBGZbDR!& z)ZfZh+Bmekq$dbcI5cMGj_14>rjx)e1U3Rz1!f`{mCmLLy?$?m z>_sAbhDDJnJ&X!5oXNN1m@6rQDnnKKq=+TSd9Dvg$2au}nGE#`*}corbeA-nJ7v*9 zS|mdz1=o5_=C`af=J|LPdMqa^+$>3to^Wm|u zr&HYG)ttq?G(YRQt&ZFAJ-?&35~wreNiNjZQzL}z76TDXl6wumeD^WW68ldf%{%XU zO}~ZxZyrC*cKK!nDP&AkH6(`)xMB;*DAFBFZIngXc&DjcG<_atdYzSV{SHpRm(k4P z*PC6Z{2mui^H4`ZR$Sg(XMTRJ<2UEL*>)QO=@;OJJaC-Is<$Y|GdDBVa*fA0_@1aE zJQ=AmoY!DKZOqW8rJeP2r$K+9WtVQXubM7Y^03^bYsR^Hb0%|$z<9T@iRtctm4}Wv NDo|2yMB8MW{0WS4Au|8~ From 47e5cf779c97870751fb06c61d002aa0bba16987 Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 15 Aug 2023 23:00:24 +0100 Subject: [PATCH 05/14] Added Mesh Metrics --- .../Mesh_Metrics/Download_MeshMetrics.py | 20 +++++ .../Solver_Features/Mesh_Metrics/Files.py | 22 ++++++ .../Solver_Features/Mesh_Metrics/README.md | 11 +++ .../Mesh_Metrics/Submit_Case.py | 24 ++++++ .../Mesh_Metrics/Submit_Mesh.py | 19 +++++ .../localFiles/Flow360_PoorSurface.json | 76 +++++++++++++++++++ 6 files changed, 172 insertions(+) create mode 100644 examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py create mode 100644 examples/Solver_Features/Mesh_Metrics/Files.py create mode 100644 examples/Solver_Features/Mesh_Metrics/README.md create mode 100644 examples/Solver_Features/Mesh_Metrics/Submit_Case.py create mode 100644 examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py create mode 100644 examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json diff --git a/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py b/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py new file mode 100644 index 0000000..d658f4f --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py @@ -0,0 +1,20 @@ +import flow360 as fl +from Files import CRM_PoorSurface + +print("Obtaining mesh and solver files") + +CRM_PoorSurface.get_files() + +print("Files accessed") + +with open('meshNameList.dat', 'r') as file: + meshNameList = file.read().splitlines() + + +my_meshes= fl.MyVolumeMeshes() +for i in range(0, len(meshNameList)): + for mesh in my_meshes: + if mesh.name == meshNameList[i]: + break + +mesh.download_file("metadata/meshMetrics.json", to_folder="./") diff --git a/examples/Solver_Features/Mesh_Metrics/Files.py b/examples/Solver_Features/Mesh_Metrics/Files.py new file mode 100644 index 0000000..e06bb00 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/Files.py @@ -0,0 +1,22 @@ +import os +from flow360.examples import base_test_case +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--localFiles', default = 0, type = int, required = False) +args = parser.parse_args() +local = args.localFiles + +base_test_case.here = os.path.dirname(os.path.abspath(__file__)) + +class CRM_PoorSurface(base_test_case.BaseTestCase): + name = "localFiles" + if local==1: + class url: + mesh = "local://Unswept_CRM_Poor_Surface.cgns" + case_json = "local://Flow360_PoorSurface.json" + else: + class url: + mesh = "PLACEHOLDER" + case_json = "PLACEHOLDER" + diff --git a/examples/Solver_Features/Mesh_Metrics/README.md b/examples/Solver_Features/Mesh_Metrics/README.md new file mode 100644 index 0000000..7cab3a4 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/README.md @@ -0,0 +1,11 @@ +To run the demo case follow these steps: + +1. Run Submit_Mesh.py -> this script will upload the mesh to the Flexcompute servers + +2. Note that the mesh metrics take a short amount of time to be calculated once the mesh is uploaded. To check whether the mesh metrics have been calculated, try downloading the meshMetrics.json file using Download_MeshMetrics.py + +3. Run Submit_Case.py -> this script will upload the case with a poor surface mesh, which will trigger mesh metrics validation warnings. + +Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". +To run with a mesh stored in the "localFiles" directory, Run SubmitMesh.py or Submit_Cases.py --localFiles 1 + diff --git a/examples/Solver_Features/Mesh_Metrics/Submit_Case.py b/examples/Solver_Features/Mesh_Metrics/Submit_Case.py new file mode 100644 index 0000000..f0e249b --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/Submit_Case.py @@ -0,0 +1,24 @@ +import flow360 as fl +from Files import CRM_PoorSurface + +print("Obtaining mesh and solver files") + +CRM_PoorSurface.get_files() + +print("Files accessed") + +with open('meshNameList.dat', 'r') as file: + meshNameList = file.read().splitlines() + + +my_meshes= fl.MyVolumeMeshes() +for i in range(0, len(meshNameList)): + for mesh in my_meshes: + if mesh.name == meshNameList[i]: + break + + +#submit case with poor surface + params = fl.Flow360Params(CRM_PoorSurface.case_json) + case = fl.Case.create("CRM_Poor_Surface", params, mesh.id) + case = case.submit() diff --git a/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py b/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py new file mode 100644 index 0000000..0959924 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py @@ -0,0 +1,19 @@ +import flow360 as fl +from Files import CRM_PoorSurface + +print("Obtaining mesh and solver files") + +CRM_PoorSurface.get_files() + +print("Files accessed") + +meshNameList=[] + +# submit mesh with poor surface +volume_mesh = fl.VolumeMesh.from_file(CRM_PoorSurface.mesh_filename, name="CRM_Poor_Surface_Mesh") +volume_mesh = volume_mesh.submit() +meshNameList.append(volume_mesh.name) + +with open('meshNameList.dat', 'w') as f: + for line in meshNameList: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json b/examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json new file mode 100644 index 0000000..7ee57a5 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json @@ -0,0 +1,76 @@ +{ + "geometry": { + "comments": { + "meshUnit": "inch" + }, + "refArea": 5, + "momentCenter": [ + 0.25, + 0.25, + 0.25 + ], + "momentLength": [ + 1, + 1, + 1 + ] + }, + "freestream": { + "muRef": 0.0000016899682361477025, + "Mach": 0.85, + "Temperature": 288.15, + "alphaAngle": 8, + "betaAngle": 0, + "comments": { + "pressure": 101325.009090375, + "densityKgPerCubicMeter": 1.225, + "speedOfSoundMeterPerSecond": 340.29400580821283, + "freestreamMeterPerSecond": 270, + "meshUnitInMeter": 0.0254 + } + }, + "boundaries": { + "fluid/wing": { + "type": "NoSlipWall" + }, + "fluid/farfield": { + "type": "Freestream" + }, + "fluid/symmetric": { + "type": "SlipWall" + } + }, + "timeStepping": { + "maxPseudoSteps": 5000, + "CFL": { + "type": "ramp", + "initial": 1, + "final": 200, + "rampSteps": 1000 + }, + "physicalSteps": 1, + "timeStepSize": "inf" + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-9, + "linearIterations": 35, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "rotationCorrection": false, + "absoluteTolerance": 1e-8, + "linearIterations": 25, + "kappaMUSCL": -1, + "orderOfAccuracy": 2 + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields": ["primitiveVars", "Mach", "qcriterion"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields": ["Cp", "Cf", "CfVec", "yPlus"] + } +} From a5fcecc889525bedf6caa4ee2c58920c7315c9ef Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 15 Aug 2023 23:45:09 +0100 Subject: [PATCH 06/14] Unedited baseline README --- README.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fcb2f9d..98fe281 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,21 @@ -To run the demo case follow these steps: +# Flow360Scripts -1. Run Submit_Cases.py -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. -2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. +## BET Translators -3. Run Convergence_Plots.py -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. +See [`examples/BET/README.md`](examples/BET/README.md) -Files.py contains reference to the location of the meshes and JSON files. -- The Flow360.json file is contained in the "Files" directory. -- The meshes are obtained by default from files stored on Flexcompute storage servers, or by setting an optional flag --localFiles to 1, locally stored files can be used from the "Files" directory. +# Developers +Run tests: +```bash +cd tests +python -m unittest +``` + +deploy +``` +poetry lock +``` From c1a1128a05cb585b86fc27e665b6adcf4aded4a5 Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Mon, 4 Sep 2023 20:42:03 +0100 Subject: [PATCH 07/14] Added no limit in cases search --- .../Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py | 3 ++- examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py | 3 ++- examples/Solver_Features/Debug_Divergence/Download_Data.py | 3 ++- examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py | 4 ++-- examples/Solver_Features/Wall_Model/Download_Data.py | 3 ++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py index abb056c..3f7c98f 100644 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py @@ -8,7 +8,7 @@ with open('caseNameList.dat', 'r') as file: caseNameList = file.read().splitlines() -my_cases = MyCases() +my_cases = MyCases(limit=None) for i in range(0, len(caseNameList)): caseFolder = os.path.join(os.getcwd(), caseNameList[i]) @@ -17,5 +17,6 @@ for case in my_cases: if case.name == caseNameList[i]: break + print(case.name) #Download the files case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py index abb056c..3f7c98f 100644 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py @@ -8,7 +8,7 @@ with open('caseNameList.dat', 'r') as file: caseNameList = file.read().splitlines() -my_cases = MyCases() +my_cases = MyCases(limit=None) for i in range(0, len(caseNameList)): caseFolder = os.path.join(os.getcwd(), caseNameList[i]) @@ -17,5 +17,6 @@ for case in my_cases: if case.name == caseNameList[i]: break + print(case.name) #Download the files case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Debug_Divergence/Download_Data.py b/examples/Solver_Features/Debug_Divergence/Download_Data.py index c527847..6d9bf26 100644 --- a/examples/Solver_Features/Debug_Divergence/Download_Data.py +++ b/examples/Solver_Features/Debug_Divergence/Download_Data.py @@ -8,7 +8,7 @@ with open('caseNameList.dat', 'r') as file: caseNameList = file.read().splitlines() -my_cases = MyCases() +my_cases = MyCases(limit=None) for i in range(0, len(caseNameList)): caseFolder = os.path.join(os.getcwd(), caseNameList[i]) @@ -17,6 +17,7 @@ for case in my_cases: if case.name == caseNameList[i]: break + print(case.name) #Download the files case.results.download(minmax_state=True, destination=caseFolder) diff --git a/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py b/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py index d658f4f..47520f0 100644 --- a/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py +++ b/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py @@ -11,10 +11,10 @@ meshNameList = file.read().splitlines() -my_meshes= fl.MyVolumeMeshes() +my_meshes= fl.MyVolumeMeshes(limit=None) for i in range(0, len(meshNameList)): for mesh in my_meshes: if mesh.name == meshNameList[i]: break - +print(mesh.name) mesh.download_file("metadata/meshMetrics.json", to_folder="./") diff --git a/examples/Solver_Features/Wall_Model/Download_Data.py b/examples/Solver_Features/Wall_Model/Download_Data.py index abb056c..3f7c98f 100644 --- a/examples/Solver_Features/Wall_Model/Download_Data.py +++ b/examples/Solver_Features/Wall_Model/Download_Data.py @@ -8,7 +8,7 @@ with open('caseNameList.dat', 'r') as file: caseNameList = file.read().splitlines() -my_cases = MyCases() +my_cases = MyCases(limit=None) for i in range(0, len(caseNameList)): caseFolder = os.path.join(os.getcwd(), caseNameList[i]) @@ -17,5 +17,6 @@ for case in my_cases: if case.name == caseNameList[i]: break + print(case.name) #Download the files case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) From 128d2c1b727bb276dfc0c6e8433718049cbcf5d2 Mon Sep 17 00:00:00 2001 From: cjdoolittle Date: Wed, 6 Sep 2023 21:30:13 -0700 Subject: [PATCH 08/14] general formatting updates to Wall_Model --- .../Wall_Model/Convergence_Plots.py | 125 +++++++++--------- .../Wall_Model/Download_Data.py | 27 ++-- examples/Solver_Features/Wall_Model/Files.py | 7 +- .../Wall_Model/Submit_Cases.py | 29 ++-- 4 files changed, 91 insertions(+), 97 deletions(-) diff --git a/examples/Solver_Features/Wall_Model/Convergence_Plots.py b/examples/Solver_Features/Wall_Model/Convergence_Plots.py index d43817e..2412cf6 100644 --- a/examples/Solver_Features/Wall_Model/Convergence_Plots.py +++ b/examples/Solver_Features/Wall_Model/Convergence_Plots.py @@ -4,93 +4,90 @@ import numpy as np import pandas as pd -def computeCLCD(data): - CL0 = np.add(data['Windsor_CL'], data['Windsor_rear_CL']) - data['CL'] = np.add(data['Windsor_supports_CL'], CL0) - CD0 = np.add(data['Windsor_CD'], data['Windsor_rear_CD']) - data['CD'] = np.add(data['Windsor_supports_CD'], CD0) +with open('caseNameList.dat', 'r') as file: + caseNameList = file.read().splitlines() + +naming = ["Wall Resolved", "Wall Modeled"] +figures = [] +axes = [] + + +def computeCLCD(data): + CL0 = np.add(data['Windsor_CL'], data['Windsor_rear_CL']) + data['CL'] = np.add(data['Windsor_supports_CL'], CL0) + CD0 = np.add(data['Windsor_CD'], data['Windsor_rear_CD']) + data['CD'] = np.add(data['Windsor_supports_CD'], CD0) def plotLoads(data, plotName): x = data['pseudo_step'] keys = ['CL', 'CD'] for ax, key in zip(axes, keys): - ax.plot(x, data[key], label = plotName) + ax.plot(x, data[key], label=plotName) ax.set_ylabel(key) ax.legend() - ax.set_xlabel('Pseudo step'); + ax.set_xlabel('Pseudo step') ax.grid(which='major', color='gray') - if (key == 'CL'): + if key == 'CL': ax.set_ylim(-0.2, -0.1) - elif (key == 'CD'): - ax.set_ylim(0.25, 0.45); + elif key == 'CD': + ax.set_ylim(0.25, 0.45) + def plotResiduals(res, plotName): x = res['pseudo_step'] keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] for ax, key, label in zip(axes, keys, labels): - ax.semilogy(x, res[key], label = plotName) + ax.semilogy(x, res[key], label=plotName) ax.set_ylabel(label) ax.legend() ax.grid(which='major', color='gray') - ax.set_xlabel('Pseudo step'); - ax.set_yticks(10.0**np.arange(-14,-3)); - ax.set_ylim([1e-13,1e-3]) - ax.set_xlim([0,10000]) - + ax.set_xlabel('Pseudo step') + ax.set_yticks(10.0**np.arange(-14, -3)) + ax.set_ylim([1e-13, 1e-3]) + ax.set_xlim([0, 10000]) - - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -naming = ["Wall Resolved", "Wall Modeled"] -figures = [] -axes = [] - def main(): - - #Plot loads convergence histories - for i in [0,1]: - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - dir_path= os.path.join(os.getcwd(),f'figures') - if not os.path.isdir(dir_path): # if directory already exists: - os.makedirs(dir_path) # make that dir - - for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(),f'{resolution}','surface_forces_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - computeCLCD(data) - plotLoads(data, naming[j]) - - figures[0].savefig(f'figures/CL.png', dpi=500); - figures[1].savefig(f'figures/CD.png', dpi=500); - - for ax in axes: - ax.cla(); - - #Plot residual convergence histories - for i in range(0,6): - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(),f'{resolution}', 'nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - plotResiduals(res, naming[j]) - - figures[0].savefig(f'figures/Cont.png', dpi=500); - figures[1].savefig(f'figures/Momx.png', dpi=500); - figures[2].savefig(f'figures/Momy.png', dpi=500); - figures[3].savefig(f'figures/Momz.png', dpi=500); - figures[4].savefig(f'figures/Energy.png', dpi=500); - figures[5].savefig(f'figures/nuHat.png', dpi=500); - + # plot loads convergence histories + for i in [0, 1]: + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + dir_path = os.path.join(os.getcwd(), f'figures') + if not os.path.isdir(dir_path): + os.makedirs(dir_path) + + for j, resolution in enumerate(caseNameList): + csvPath = os.path.join(os.getcwd(), f'{resolution}', 'surface_forces_v2.csv') + data = pd.read_csv(csvPath, skipinitialspace=True) + computeCLCD(data) + plotLoads(data, naming[j]) + + figures[0].savefig(f'figures/CL.png', dpi=500) + figures[1].savefig(f'figures/CD.png', dpi=500) + + for ax in axes: + ax.cla() + + # plot residual convergence histories + for i in range(0, 6): + fig, ax = plt.subplots(figsize=(8, 6)) + figures.append(fig) + axes.append(ax) + for j, resolution in enumerate(caseNameList): + csvPath = os.path.join(os.getcwd(), f'{resolution}', 'nonlinear_residual_v2.csv') + res = pd.read_csv(csvPath, skipinitialspace=True) + plotResiduals(res, naming[j]) + + figures[0].savefig(f'figures/Cont.png', dpi=500) + figures[1].savefig(f'figures/Momx.png', dpi=500) + figures[2].savefig(f'figures/Momy.png', dpi=500) + figures[3].savefig(f'figures/Momz.png', dpi=500) + figures[4].savefig(f'figures/Energy.png', dpi=500) + figures[5].savefig(f'figures/nuHat.png', dpi=500) if __name__ == '__main__': diff --git a/examples/Solver_Features/Wall_Model/Download_Data.py b/examples/Solver_Features/Wall_Model/Download_Data.py index 3f7c98f..2dceeb7 100644 --- a/examples/Solver_Features/Wall_Model/Download_Data.py +++ b/examples/Solver_Features/Wall_Model/Download_Data.py @@ -2,21 +2,20 @@ import flow360 as fl from flow360 import MyCases - -#read in caseNameList - +# read in caseNameList with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() + caseNameList = file.read().splitlines() +# get case list from Flow360 my_cases = MyCases(limit=None) -for i in range(0, len(caseNameList)): - caseFolder = os.path.join(os.getcwd(), caseNameList[i]) - os.makedirs(caseFolder, exist_ok = True) - #Find the latest case with the name corresponding to the name in caseNameList - for case in my_cases: - if case.name == caseNameList[i]: - break - print(case.name) - #Download the files - case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) +for caseName in caseNameList: + caseFolder = os.path.join(os.getcwd(), caseName) + os.makedirs(caseFolder, exist_ok=True) + # find the latest case with name corresponding to caseNameList + for case in my_cases: + if case.name == caseName: + break + print(case.name) + # download the files + case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Wall_Model/Files.py b/examples/Solver_Features/Wall_Model/Files.py index e4a2491..365daf9 100644 --- a/examples/Solver_Features/Wall_Model/Files.py +++ b/examples/Solver_Features/Wall_Model/Files.py @@ -3,7 +3,7 @@ import argparse parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default = 0, type = int, required = False) +parser.add_argument('--localFiles', default=0, type=int, required=False) args = parser.parse_args() local = args.localFiles @@ -12,7 +12,7 @@ class WallResolved(base_test_case.BaseTestCase): name = "localFiles" - if local ==1: + if local == 1: class url: mesh = "local://Windsor_Wall_Resolved_1e-06.b8.ugrid" case_json = "local://Flow360.json" @@ -23,7 +23,8 @@ class url: class WallModel(base_test_case.BaseTestCase): name = "localFiles" - if local==1: + + if local == 1: class url: mesh = "local://Windsor_Wall_Model_5e-04.b8.ugrid" else: diff --git a/examples/Solver_Features/Wall_Model/Submit_Cases.py b/examples/Solver_Features/Wall_Model/Submit_Cases.py index 0072c25..557a68e 100644 --- a/examples/Solver_Features/Wall_Model/Submit_Cases.py +++ b/examples/Solver_Features/Wall_Model/Submit_Cases.py @@ -3,44 +3,41 @@ from Files import WallResolved, WallModel print("Obtaining mesh and solver files") - - WallResolved.get_files() WallModel.get_files() print("Files accessed") -caseNameList=[] +caseNameList = [] # submit wall resolved mesh volume_mesh = fl.VolumeMesh.from_file(WallResolved.mesh_filename, name="Windsor_Wall_Resolved_Mesh") volume_mesh = volume_mesh.submit() - # submit wall model mesh volume_mesh2 = fl.VolumeMesh.from_file(WallModel.mesh_filename, name="Windsor_Wall_Modeled_Mesh") volume_mesh2 = volume_mesh2.submit() - # submit wall-resolved case using json file +# submit wall-resolved case using json file params = fl.Flow360Params(WallResolved.case_json) case = fl.Case.create("Windsor_Wall_Resolved", params, volume_mesh.id) caseNameList.append(case.name) case = case.submit() -# Change noSlipWall to wallFunction in params - +# change NoSlipWall to WallFunction in params Boundaries = params.boundaries -params.boundaries = Boundaries.copy(update={ "1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), "4": fl.WallFunction(name="Flow.CFDWT.Floor"), "8": fl.WallFunction(name="Windsor"), "9": fl.WallFunction(name="Windsor_rear"), "10": fl.WallFunction(name="Windsor_supports")}) +params.boundaries = Boundaries.copy(update={"1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), + "4": fl.WallFunction(name="Flow.CFDWT.Floor"), + "8": fl.WallFunction(name="Windsor"), + "9": fl.WallFunction(name="Windsor_rear"), + "10": fl.WallFunction(name="Windsor_supports")}) # submit wall-modeled case using updated parameters - -case = fl.Case.create("Windsor_Wall_Modeled", params, volume_mesh2.id) -caseNameList.append(case.name) -case = case.submit() +case2 = fl.Case.create("Windsor_Wall_Modeled", params, volume_mesh2.id) +caseNameList.append(case2.name) +case2 = case2.submit() # dump case names for use in download and post-processing scripts - with open('caseNameList.dat', 'w') as f: - for line in caseNameList: - f.write(f"{line}\n") - + for line in caseNameList: + f.write(f"{line}\n") From 3c36d9f54a4bb65cea9c5c2e0a5ab04f2e1166d1 Mon Sep 17 00:00:00 2001 From: cjdoolittle Date: Wed, 6 Sep 2023 22:15:31 -0700 Subject: [PATCH 09/14] refactor Convergence_Plots.py --- .../Wall_Model/Convergence_Plots.py | 70 +++++++++---------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/examples/Solver_Features/Wall_Model/Convergence_Plots.py b/examples/Solver_Features/Wall_Model/Convergence_Plots.py index 2412cf6..04f198d 100644 --- a/examples/Solver_Features/Wall_Model/Convergence_Plots.py +++ b/examples/Solver_Features/Wall_Model/Convergence_Plots.py @@ -4,11 +4,11 @@ import numpy as np import pandas as pd - with open('caseNameList.dat', 'r') as file: caseNameList = file.read().splitlines() -naming = ["Wall Resolved", "Wall Modeled"] +loads = ['CL', 'CD'] +residuals = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] figures = [] axes = [] @@ -22,26 +22,23 @@ def computeCLCD(data): def plotLoads(data, plotName): x = data['pseudo_step'] - keys = ['CL', 'CD'] - for ax, key in zip(axes, keys): - ax.plot(x, data[key], label=plotName) - ax.set_ylabel(key) + for ax, load in zip(axes, loads): + ax.plot(x, data[load], label=plotName) + ax.set_ylabel(load) ax.legend() ax.set_xlabel('Pseudo step') ax.grid(which='major', color='gray') - if key == 'CL': + if load == 'CL': ax.set_ylim(-0.2, -0.1) - elif key == 'CD': + elif load == 'CD': ax.set_ylim(0.25, 0.45) -def plotResiduals(res, plotName): - x = res['pseudo_step'] - keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] - labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] - for ax, key, label in zip(axes, keys, labels): - ax.semilogy(x, res[key], label=plotName) - ax.set_ylabel(label) +def plotResiduals(data, plotName): + x = data['pseudo_step'] + for ax, res in zip(axes, residuals): + ax.semilogy(x, data[res], label=plotName) + ax.set_ylabel(res) ax.legend() ax.grid(which='major', color='gray') ax.set_xlabel('Pseudo step') @@ -51,45 +48,42 @@ def plotResiduals(res, plotName): def main(): - # plot loads convergence histories - for i in [0, 1]: + # 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) - dir_path = os.path.join(os.getcwd(), f'figures') - if not os.path.isdir(dir_path): - os.makedirs(dir_path) - for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(), f'{resolution}', 'surface_forces_v2.csv') + # calculate and plot loads convergence histories + for caseName in caseNameList: + csvPath = os.path.join(os.getcwd(), caseName, 'surface_forces_v2.csv') data = pd.read_csv(csvPath, skipinitialspace=True) computeCLCD(data) - plotLoads(data, naming[j]) + plotLoads(data, caseName) - figures[0].savefig(f'figures/CL.png', dpi=500) - figures[1].savefig(f'figures/CD.png', dpi=500) + # save loads figures + 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 - for i in range(0, 6): + for res in residuals: fig, ax = plt.subplots(figsize=(8, 6)) figures.append(fig) axes.append(ax) - for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(), f'{resolution}', 'nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - plotResiduals(res, naming[j]) - - figures[0].savefig(f'figures/Cont.png', dpi=500) - figures[1].savefig(f'figures/Momx.png', dpi=500) - figures[2].savefig(f'figures/Momy.png', dpi=500) - figures[3].savefig(f'figures/Momz.png', dpi=500) - figures[4].savefig(f'figures/Energy.png', dpi=500) - figures[5].savefig(f'figures/nuHat.png', dpi=500) + for caseName in caseNameList: + csvPath = os.path.join(os.getcwd(), caseName, 'nonlinear_residual_v2.csv') + data = pd.read_csv(csvPath, skipinitialspace=True) + plotResiduals(data, caseName) + for i, res in enumerate(residuals): + figures[i].savefig(os.path.join(dir_path, res + '.png'), dpi=500) if __name__ == '__main__': main() - From f4b8884835e054ab588f66d5f254f1332dde9499 Mon Sep 17 00:00:00 2001 From: cjdoolittle Date: Wed, 6 Sep 2023 22:22:17 -0700 Subject: [PATCH 10/14] formatting README.md --- examples/Solver_Features/Wall_Model/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Solver_Features/Wall_Model/README.md b/examples/Solver_Features/Wall_Model/README.md index de9aaa0..6075ba4 100644 --- a/examples/Solver_Features/Wall_Model/README.md +++ b/examples/Solver_Features/Wall_Model/README.md @@ -1,12 +1,12 @@ To run the demo case follow these steps: -1. Run Submit_Cases.py -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. +1. Run `python Submit_Cases.py` -> this script will download[^1] both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. -2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. +2. Run `python Download_Data.py` -> this script will download the csv files containing the loads and residual histories. -3. Run Convergence_Plots.py -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. +3. Run `python Convergence_Plots.py` -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. -Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". +[^1] Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 From 94116779239f228e7a1c3c1cf94757109d6b8758 Mon Sep 17 00:00:00 2001 From: cjdoolittle <92044127+cjdoolittle@users.noreply.github.com> Date: Wed, 6 Sep 2023 22:26:43 -0700 Subject: [PATCH 11/14] Update README.md --- examples/Solver_Features/Wall_Model/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/Solver_Features/Wall_Model/README.md b/examples/Solver_Features/Wall_Model/README.md index 6075ba4..ac3316d 100644 --- a/examples/Solver_Features/Wall_Model/README.md +++ b/examples/Solver_Features/Wall_Model/README.md @@ -6,8 +6,7 @@ To run the demo case follow these steps: 3. Run `python Convergence_Plots.py` -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. -[^1] Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". -To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 +[^1] Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". To run with a mesh stored in the "localFiles" directory, run `python Submit_Cases.py --localFiles 1`. From 6bc7998c747425a7e912202e38cf64c706252bb8 Mon Sep 17 00:00:00 2001 From: cjdoolittle Date: Mon, 11 Sep 2023 16:39:10 -0700 Subject: [PATCH 12/14] updating S3 URLs for downloads --- examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py | 4 ++-- examples/Solver_Features/Adaptive_CFL/XV15/Files.py | 4 ++-- examples/Solver_Features/Debug_Divergence/Files.py | 8 ++++---- examples/Solver_Features/Mesh_Metrics/Files.py | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py index c190f8f..70d0be2 100644 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py @@ -17,5 +17,5 @@ class url: case_json = "local://Flow360.json" else: class url: - mesh = "PLACEHOLDER" - case_json = "PLACEHOLDER" + mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Adaptive_CFL/ONERAM6/mesh.lb8.ugrid.bz2" + case_json = "local://Flow360.json" diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Files.py b/examples/Solver_Features/Adaptive_CFL/XV15/Files.py index 75c6034..6f615c1 100644 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Files.py +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Files.py @@ -17,6 +17,6 @@ class url: case_json = "local://Flow360.json" else: class url: - mesh = "PLACEHOLDER" - case_json = "PLACEHOLDER" + mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Adaptive_CFL/XV15/xv15_airplane_pitch26.cgns.bz2" + case_json = "local://Flow360.json" diff --git a/examples/Solver_Features/Debug_Divergence/Files.py b/examples/Solver_Features/Debug_Divergence/Files.py index 0d468a6..8bf6af7 100644 --- a/examples/Solver_Features/Debug_Divergence/Files.py +++ b/examples/Solver_Features/Debug_Divergence/Files.py @@ -17,8 +17,8 @@ class url: case_json = "local://Flow360_PoorSurface.json" else: class url: - mesh = "PLACEHOLDER" - case_json = "PLACEHOLDER" + mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Mesh_Metrics/Unswept_CRM_Poor_Surface.cgns.bz2" + case_json = "local://Flow360_PoorSurface.json" class CRM_AD(base_test_case.BaseTestCase): name = "localFiles" @@ -28,6 +28,6 @@ class url: case_json = "local://Flow360_AD.json" else: class url: - mesh = "PLACEHOLDER" - case_json = "PLACEHOLDER" + mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Debug_Divergence/Unswept_CRM_AD.cgns.bz2" + case_json = "local://Flow360_AD.json" diff --git a/examples/Solver_Features/Mesh_Metrics/Files.py b/examples/Solver_Features/Mesh_Metrics/Files.py index e06bb00..67dd9d9 100644 --- a/examples/Solver_Features/Mesh_Metrics/Files.py +++ b/examples/Solver_Features/Mesh_Metrics/Files.py @@ -17,6 +17,6 @@ class url: case_json = "local://Flow360_PoorSurface.json" else: class url: - mesh = "PLACEHOLDER" - case_json = "PLACEHOLDER" + mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Mesh_Metrics/Unswept_CRM_Poor_Surface.cgns.bz2" + case_json = "local://Flow360_PoorSurface.json" From edb1617a2de124427573a082128cb61a6b9371c6 Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 5 Dec 2023 16:49:54 +0000 Subject: [PATCH 13/14] Script Revisions according to Flow360Scripts Guidelines --- .../ONERAM6/Convergence_Plots_10.py | 91 ----- .../ONERAM6/Convergence_Plots_3p06.py | 92 ----- .../Adaptive_CFL/ONERAM6/Download_Data.py | 22 -- .../Adaptive_CFL/ONERAM6/Files.py | 21 -- .../ONERAM6/{localFiles => }/Flow360.json | 0 .../Adaptive_CFL/ONERAM6/README.md | 13 +- .../Adaptive_CFL/ONERAM6/Submit_Cases.py | 59 ---- .../ONERAM6/convergence_plots_10.py | 89 +++++ .../ONERAM6/convergence_plots_3p06.py | 89 +++++ .../Adaptive_CFL/ONERAM6/download_data.py | 29 ++ .../ONERAM6/submit_cases_from_downloads.py | 64 ++++ .../ONERAM6/submit_cases_from_id.py | 50 +++ .../Adaptive_CFL/XV15/ConvergencePlots.py | 78 ----- .../Adaptive_CFL/XV15/Download_Data.py | 22 -- .../Adaptive_CFL/XV15/Files.py | 22 -- .../XV15/{localFiles => }/Flow360.json | 0 .../Adaptive_CFL/XV15/Flow360_New.json | 86 +++++ .../Adaptive_CFL/XV15/README.md | 13 +- .../Adaptive_CFL/XV15/Submit_Cases.py | 63 ---- .../Adaptive_CFL/XV15/convergence_plots.py | 68 ++++ .../Adaptive_CFL/XV15/download_data.py | 27 ++ .../XV15/submit_cases_from_downloads.py | 62 ++++ .../Adaptive_CFL/XV15/submit_cases_from_id.py | 45 +++ .../Debug_Divergence/Download_Data.py | 23 -- .../Solver_Features/Debug_Divergence/Files.py | 33 -- .../{localFiles => }/Flow360_AD.json | 0 .../{localFiles => }/Flow360_PoorSurface.json | 0 .../Print_Divergence_Locations.py | 27 -- .../Debug_Divergence/{README => README.md} | 8 +- .../Debug_Divergence/Submit_Cases.py | 37 -- .../Debug_Divergence/download_data.py | 27 ++ .../print_divergence_locations.py | 45 +++ .../submit_cases_from_downloads.py | 48 +++ .../Debug_Divergence/submit_cases_from_id.py | 25 ++ .../Mesh_Metrics/Download_MeshMetrics.py | 20 -- .../Solver_Features/Mesh_Metrics/Files.py | 22 -- .../{localFiles => }/Flow360_PoorSurface.json | 0 .../Solver_Features/Mesh_Metrics/README.md | 12 +- .../Mesh_Metrics/Submit_Case.py | 24 -- .../Mesh_Metrics/Submit_Mesh.py | 19 -- .../Mesh_Metrics/download_mesh_metrics.py | 16 + .../Mesh_Metrics/meshMetrics.json | 317 ++++++++++++++++++ .../Mesh_Metrics/submit_case_from_mesh_id.py | 21 ++ .../submit_case_from_mesh_name.py | 18 + .../Mesh_Metrics/submit_mesh_from_download.py | 26 ++ .../Wall_Model/Convergence_Plots.py | 89 ----- .../Wall_Model/Download_Data.py | 21 -- examples/Solver_Features/Wall_Model/Files.py | 32 -- .../Wall_Model/{localFiles => }/Flow360.json | 0 examples/Solver_Features/Wall_Model/README.md | 9 +- .../Wall_Model/Submit_Cases.py | 43 --- .../Wall_Model/convergence_plots.py | 94 ++++++ .../Wall_Model/download_data.py | 29 ++ .../Wall_Model/submit_cases_from_downloads.py | 64 ++++ .../Wall_Model/submit_cases_from_id.py | 37 ++ 55 files changed, 1400 insertions(+), 891 deletions(-) delete mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py rename examples/Solver_Features/Adaptive_CFL/ONERAM6/{localFiles => }/Flow360.json (100%) delete mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_10.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_3p06.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/download_data.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_downloads.py create mode 100644 examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_id.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py delete mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Files.py rename examples/Solver_Features/Adaptive_CFL/XV15/{localFiles => }/Flow360.json (100%) create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json delete mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/convergence_plots.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/download_data.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_downloads.py create mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_id.py delete mode 100644 examples/Solver_Features/Debug_Divergence/Download_Data.py delete mode 100644 examples/Solver_Features/Debug_Divergence/Files.py rename examples/Solver_Features/Debug_Divergence/{localFiles => }/Flow360_AD.json (100%) rename examples/Solver_Features/Debug_Divergence/{localFiles => }/Flow360_PoorSurface.json (100%) delete mode 100644 examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py rename examples/Solver_Features/Debug_Divergence/{README => README.md} (51%) delete mode 100644 examples/Solver_Features/Debug_Divergence/Submit_Cases.py create mode 100644 examples/Solver_Features/Debug_Divergence/download_data.py create mode 100644 examples/Solver_Features/Debug_Divergence/print_divergence_locations.py create mode 100644 examples/Solver_Features/Debug_Divergence/submit_cases_from_downloads.py create mode 100644 examples/Solver_Features/Debug_Divergence/submit_cases_from_id.py delete mode 100644 examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py delete mode 100644 examples/Solver_Features/Mesh_Metrics/Files.py rename examples/Solver_Features/Mesh_Metrics/{localFiles => }/Flow360_PoorSurface.json (100%) delete mode 100644 examples/Solver_Features/Mesh_Metrics/Submit_Case.py delete mode 100644 examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py create mode 100644 examples/Solver_Features/Mesh_Metrics/download_mesh_metrics.py create mode 100644 examples/Solver_Features/Mesh_Metrics/meshMetrics.json create mode 100644 examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_id.py create mode 100644 examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_name.py create mode 100644 examples/Solver_Features/Mesh_Metrics/submit_mesh_from_download.py delete mode 100644 examples/Solver_Features/Wall_Model/Convergence_Plots.py delete mode 100644 examples/Solver_Features/Wall_Model/Download_Data.py delete mode 100644 examples/Solver_Features/Wall_Model/Files.py rename examples/Solver_Features/Wall_Model/{localFiles => }/Flow360.json (100%) delete mode 100644 examples/Solver_Features/Wall_Model/Submit_Cases.py create mode 100644 examples/Solver_Features/Wall_Model/convergence_plots.py create mode 100644 examples/Solver_Features/Wall_Model/download_data.py create mode 100644 examples/Solver_Features/Wall_Model/submit_cases_from_downloads.py create mode 100644 examples/Solver_Features/Wall_Model/submit_cases_from_id.py diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py deleted file mode 100644 index f61b47e..0000000 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_10.py +++ /dev/null @@ -1,91 +0,0 @@ -import matplotlib.pyplot as plt -from collections import defaultdict -import os, csv -import numpy as np -import pandas as pd - - - - -def plotLoads(data, plotName): - axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) - axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) - axes[0].set_ylabel('CL'); - axes[1].set_ylabel('CD'); - axes[0].set_ylim(0.45, 0.8); - axes[1].set_ylim(0.1, 0.15); - - for ax in axes: - ax.legend() - ax.set_xlabel('Pseudo step'); - ax.grid(which='major', color='gray') - -def plotResiduals(res, plotName): - x = res['pseudo_step'] - keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] - labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] - for ax, key, label in zip(axes, keys, labels): - for j, key in enumerate(keys): - if plotName =="Ramp": - ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) - else: - ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) - ax.set_ylabel('Residuals') - ax.legend() - ax.set_title("ONERAM6 10.0 deg") - ax.grid(which='major', color='gray') - ax.set_xlabel('Pseudo step'); - ax.set_yticks(10.0**np.arange(-14,-3)); - ax.set_ylim([1e-10,1e-3]) - ax.set_xlim([0,8000]) - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -naming = ["Ramp", "Adaptive", "Ramp", "Adaptive"] -figures = [] -axes = [] - -def main(): - - #Plot loads convergence histories - for i in [0,1]: - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - dir_path= os.path.join(os.getcwd(),f'figures') - if not os.path.isdir(dir_path): # if directory already exists: - os.makedirs(dir_path) # make that dir - - for j, resolution in enumerate(caseNameList): - if "10" in resolution: - csvPath = os.path.join(os.getcwd(),f'{resolution}', 'total_forces_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - plotLoads(data, naming[j]) - - - figures[0].savefig(f'figures/CL_AoA10.png', dpi=500); - figures[1].savefig(f'figures/CD_AoA10.png', dpi=500); - - for i in range(0,2): - axes[i].cla(); - - #Plot residual convergence histories - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - for j, resolution in enumerate(caseNameList): - if "10" in resolution: - if "ADAPTIVE" in resolution: - figures[0].gca().set_prop_cycle(None) - csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - plotResiduals(res, naming[j]) - - figures[0].savefig(f'figures/Residuals_AoA10.png', dpi=500); - - - -if __name__ == '__main__': - main() - diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py deleted file mode 100644 index e8f3118..0000000 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Convergence_Plots_3p06.py +++ /dev/null @@ -1,92 +0,0 @@ -import matplotlib.pyplot as plt -from collections import defaultdict -import os, csv -import numpy as np -import pandas as pd - - - - -def plotLoads(data, plotName): - axes[0].plot(data['pseudo_step'], data['CL'], label=plotName) - axes[1].plot(data['pseudo_step'], data['CD'], label=plotName) - axes[0].set_ylabel('CL'); - axes[1].set_ylabel('CD'); - axes[0].set_ylim(0.25, 0.3); - axes[1].set_ylim(0.0, 0.05); - - for ax in axes: - ax.legend() - ax.set_xlabel('Pseudo step'); - ax.grid(which='major', color='gray') - -def plotResiduals(res, plotName): - x = res['pseudo_step'] - keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] - labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] - for ax, key, label in zip(axes, keys, labels): - for j, key in enumerate(keys): - if plotName =="Ramp": - ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) - else: - ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) - ax.set_ylabel('Residuals') - ax.legend() - ax.set_title("ONERAM6 -3.06 deg") - ax.grid(which='major', color='gray') - ax.set_xlabel('Pseudo step'); - ax.set_yticks(10.0**np.arange(-14,-3)); - ax.set_ylim([1e-10,1e-3]) - ax.set_xlim([0,4000]) - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -naming = ["Ramp", "Adaptive"] -figures = [] -axes = [] - -def main(): - - #Plot loads convergence histories - for i in [0,1]: - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - dir_path= os.path.join(os.getcwd(),f'figures') - if not os.path.isdir(dir_path): # if directory already exists: - os.makedirs(dir_path) # make that dir - - for j, resolution in enumerate(caseNameList): - if "3p06" in resolution: - - csvPath = os.path.join(os.getcwd(),f'{resolution}','total_forces_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - plotLoads(data, naming[j]) - - - figures[0].savefig(f'figures/CL_AoA3p06.png', dpi=500); - figures[1].savefig(f'figures/CD_AoA3p06.png', dpi=500); - - for i in range(0,2): - axes[i].cla(); - - #Plot residual convergence histories - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - for j, resolution in enumerate(caseNameList): - if "3p06" in resolution: - if "ADAPTIVE" in resolution: - figures[0].gca().set_prop_cycle(None) - csvPath = os.path.join(os.getcwd(),f'{resolution}', 'nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - plotResiduals(res, naming[j]) - - figures[0].savefig(f'figures/Residuals_AoA3p06.png', dpi=500); - - - -if __name__ == '__main__': - main() - diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py deleted file mode 100644 index 3f7c98f..0000000 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Download_Data.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import flow360 as fl -from flow360 import MyCases - - -#read in caseNameList - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -my_cases = MyCases(limit=None) - -for i in range(0, len(caseNameList)): - caseFolder = os.path.join(os.getcwd(), caseNameList[i]) - os.makedirs(caseFolder, exist_ok = True) - #Find the latest case with the name corresponding to the name in caseNameList - for case in my_cases: - if case.name == caseNameList[i]: - break - print(case.name) - #Download the files - case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py deleted file mode 100644 index 70d0be2..0000000 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Files.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -from flow360.examples import base_test_case -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default = 0, type = int, required = False) -args = parser.parse_args() -local = args.localFiles - -base_test_case.here = os.path.dirname(os.path.abspath(__file__)) - -class ONERAM6(base_test_case.BaseTestCase): - name = "localFiles" - if local==1: - class url: - mesh = "local://mesh.lb8.ugrid" - case_json = "local://Flow360.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Adaptive_CFL/ONERAM6/mesh.lb8.ugrid.bz2" - case_json = "local://Flow360.json" diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Flow360.json similarity index 100% rename from examples/Solver_Features/Adaptive_CFL/ONERAM6/localFiles/Flow360.json rename to examples/Solver_Features/Adaptive_CFL/ONERAM6/Flow360.json diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md b/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md index e823088..7717ae1 100644 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/README.md @@ -1,12 +1,9 @@ -To run the demo case follow these steps: - -1. Run Submit_Cases.py -> this script will obtain the mesh and submit ramp and adaptive CFL cases for the ONERAM6 wing at two angles of attack +The following example demonstrates the use of adaptive CFL for the ONERAM6 wing -2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. - -3. Run Convergence_Plots_3p06.py and Convergence_Plots_10.py -> these script will cross-plot the load and residual convergence histories for the ramp and adaptive CFL cases at two angles of attack. +To run the demo case follow these steps: -Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". -To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 +1. Run `python submit_cases_from_downloads.py` -> this script will download the ONERAM6 mesh, and upload it to the Flexcompute servers. The cases will also be submitted for both adaptive and ramp CFL at two angles of attack. Alternatively the script `submit_cases_from_id.py` can also be used to run the cases from meshes already uploaded to Flexcompute servers. +2. Run `python download_data.py` -> this script will download the csv files containing the loads and residual histories at two angles of attack +3. Run `python convergence_plots_3p06.py` and `python convergence_plots_10.py` -> these scripts will cross-plot the load and residual convergence histories for the ramp and adaptive CFL cases at two angles of attack. diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py deleted file mode 100644 index c74366d..0000000 --- a/examples/Solver_Features/Adaptive_CFL/ONERAM6/Submit_Cases.py +++ /dev/null @@ -1,59 +0,0 @@ -import os -import flow360 as fl -from Files import ONERAM6 - -print("Obtaining mesh and solver files") - -ONERAM6.get_files() - -print("Files accessed") - -caseNameList=[] - -# submit mesh -volume_mesh = fl.VolumeMesh.from_file(ONERAM6.mesh_filename, name="ONERAM6_Mesh") -volume_mesh = volume_mesh.submit() - - -params = fl.Flow360Params(ONERAM6.case_json) - -#submit ramp CFL case at alpha = 3.06 -case = fl.Case.create("ONERAM6_3p06_RAMP", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -#change CFL type to adaptive -params.time_stepping.CFL.type = "adaptive" - -#submit adaptive CFL case at alpha = 3.06 -case = fl.Case.create("ONERAM6_3p06_ADAPTIVE", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -#change CFL type to ramp, modify time stepping settings and increase alpha to 10 -params.time_stepping.CFL.type = "ramp" -params.time_stepping.max_pseudo_steps = 8000 -params.time_stepping.CFL.initial = 1 -params.time_stepping.CFL.final = 20 -params.time_stepping.CFL.ramp_steps = 200 -params.freestream.alpha = 10 - -#submit ramp CFL case at alpha = 10 -case = fl.Case.create("ONERAM6_10_RAMP", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - - -#change CFL type to adaptive -params.time_stepping.CFL.type = "adaptive" - -#submit adaptive CFL case at alpha = 10 -case = fl.Case.create("ONERAM6_10_ADAPTIVE", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -# dump case names for use in download and post-processing scripts - -with open('caseNameList.dat', 'w') as f: - for line in caseNameList: - f.write(f"{line}\n") diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_10.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_10.py new file mode 100644 index 0000000..30e0c5a --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_10.py @@ -0,0 +1,89 @@ +"""Plot the loads and residuals convergence plots for the ramp and adaptive CFL cases at 10 degrees""" + +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.45, 0.8) + elif load == "CD": + ax.set_ylim(0.1, 0.15) + + +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 "RAMP" 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("ONERAM6 -10 deg") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -3)) + ax.set_ylim([1e-10, 1e-3]) + ax.set_xlim([0, 8000]) + + +# 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: + if "10" in case_name: + 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 + "_AoA10.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 "10" in case_name: + if "ADAPTIVE" 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_AoA10.png"), dpi=500) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_3p06.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_3p06.py new file mode 100644 index 0000000..4e3bedf --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/convergence_plots_3p06.py @@ -0,0 +1,89 @@ +"""Plot the loads and residuals convergence plots for the ramp and adaptive CFL cases at 3.06 degrees""" + +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.25, 0.3) + elif load == "CD": + ax.set_ylim(0.0, 0.05) + + +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 "RAMP" 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("ONERAM6 -3.06 deg") + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -3)) + ax.set_ylim([1e-10, 1e-3]) + ax.set_xlim([0, 4000]) + + +# 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: + if "3p06" in case_name: + 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 + "_AoA3p06.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 "3p06" in case_name: + if "ADAPTIVE" 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_AoA3p06.png"), dpi=500) diff --git a/examples/Solver_Features/Adaptive_CFL/ONERAM6/download_data.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/download_data.py new file mode 100644 index 0000000..2429730 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/download_data.py @@ -0,0 +1,29 @@ +"""Download the results for the ramp and adaptive CFL cases at both angles of attack""" + +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/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_downloads.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_downloads.py new file mode 100644 index 0000000..2876571 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_downloads.py @@ -0,0 +1,64 @@ +"""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 = "PLACEHOLDER" +MESH_FILENAME = "mesh.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 ramp CFL case at alpha = 3.06 +case = fl.Case.create("ONERAM6_3p06_RAMP", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +# submit adaptive CFL case at alpha = 3.06 +case2 = fl.Case.create("ONERAM6_3p06_ADAPTIVE", params, volume_mesh.id) +case_name_list.append(case2.name) +case2 = case2.submit() + +# change CFL type to ramp, modify time stepping settings and increase alpha to 10 +params.time_stepping.CFL.type = "ramp" +params.time_stepping.max_pseudo_steps = 8000 +params.time_stepping.CFL.initial = 1 +params.time_stepping.CFL.final = 20 +params.time_stepping.CFL.ramp_steps = 200 +params.freestream.alpha = 10 + +# submit ramp CFL case at alpha = 10 +case3 = fl.Case.create("ONERAM6_10_RAMP", params, volume_mesh.id) +case_name_list.append(case3.name) +case3 = case3.submit() + + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +# submit adaptive CFL case at alpha = 10 +case4 = fl.Case.create("ONERAM6_10_ADAPTIVE", params, volume_mesh.id) +case_name_list.append(case4.name) +case4 = case4.submit() + +# dump case names 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/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_id.py b/examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_id.py new file mode 100644 index 0000000..5274525 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/ONERAM6/submit_cases_from_id.py @@ -0,0 +1,50 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID = "3849aa75-56f7-4921-ae0e-8b5cf45ed58a" + +params = fl.Flow360Params("Flow360.json") + +# submit ramp CFL case at alpha = 3.06 +case = fl.Case.create("ONERAM6_3p06_RAMP", params, MESH_ID) +case_name_list.append(case.name) +case = case.submit() + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +# submit adaptive CFL case at alpha = 3.06 +case2 = fl.Case.create("ONERAM6_3p06_ADAPTIVE", params, MESH_ID) +case_name_list.append(case2.name) +case2 = case2.submit() + +# change CFL type to ramp, modify time stepping settings and increase alpha to 10 +params.time_stepping.CFL.type = "ramp" +params.time_stepping.max_pseudo_steps = 8000 +params.time_stepping.CFL.initial = 1 +params.time_stepping.CFL.final = 20 +params.time_stepping.CFL.ramp_steps = 200 +params.freestream.alpha = 10 + +# submit ramp CFL case at alpha = 10 +case3 = fl.Case.create("ONERAM6_10_RAMP", params, MESH_ID) +case_name_list.append(case3.name) +case3 = case3.submit() + + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +# submit adaptive CFL case at alpha = 10 +case4 = fl.Case.create("ONERAM6_10_ADAPTIVE", params, MESH_ID) +case_name_list.append(case4.name) +case4 = case4.submit() + +# dump case names 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/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py b/examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py deleted file mode 100644 index 5a3a540..0000000 --- a/examples/Solver_Features/Adaptive_CFL/XV15/ConvergencePlots.py +++ /dev/null @@ -1,78 +0,0 @@ -import matplotlib.pyplot as plt -from collections import defaultdict -import os, csv, json -import numpy as np -import pandas as pd - -def addAccumPseudoStep(history): - pseudoSteps = history['pseudo_step'] - accum = list() - accum.append(0) - for i in range(1,len(pseudoSteps)): - if pseudoSteps[i] > pseudoSteps[i-1]: - accum.append(accum[-1]+abs(pseudoSteps[i] - pseudoSteps[i-1])) - else: - accum.append(accum[-1]+1) - history['accum_pseudo_step'] = accum - - -def plotResiduals(res, caseName, plotName): - x = res['accum_pseudo_step'] - keys = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] - labels = ['Cont Residual', 'Momx Residual', 'Momy Residual', 'Momz Residual', 'Energy Residual', 'nuHat Residual'] - for ax, key, label in zip(axes, keys, labels): - for j, key in enumerate(keys): - if plotName =="Ramp": - ax.semilogy(x, res[key], label = plotName + ' ' + labels[j]) - else: - ax.semilogy(x, res[key], "--", label = plotName + ' ' + labels[j]) - ax.legend(loc='upper right') - ax.grid(which='major', color='gray') - - ax.set_title("XV15 Rotor - Residuals") - ax.set_xlabel('Accumulated Pseudo step'); - ax.set_yticks(10.0**np.arange(-11,-3)); - ax.set_ylim([1e-9,1e-3]) - ax.set_xlim([3000,4000]) - ax.set_ylabel('Residuals') - - -caseNameList = ["XV15_2nd_order_ramp_forked", "XV15_2nd_order_adaptive_forked"] -naming= ["Ramp", "Adaptive"] -figures = [] -axes = [] - -def main(): - fig, ax = plt.subplots(figsize=(8,6)) - figures.append(fig) - axes.append(ax) - dir_path= os.path.join(os.getcwd(),f'figures') - if not os.path.isdir(dir_path): # if directory already exists: - os.makedirs(dir_path) # make that dir - - for j, resolution in enumerate(caseNameList): - csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - addAccumPseudoStep(res) - plotResiduals(res, resolution, naming[j]) - figures[0].gca().set_prop_cycle(None) - figures[0].savefig(f'figures/Residuals.png', dpi=500); - axes[0].set_xlim([3450,3550]) - figures[0].savefig(f'figures/ResidualsZoomed.png', dpi=500); - - caseNameList2 = ["XV15_2nd_order_adaptive"] - naming2= ["Adaptive"] - for ax in axes: - ax.cla(); - - for j, resolution in enumerate(caseNameList2): - csvPath = os.path.join(os.getcwd(),f'{resolution}','nonlinear_residual_v2.csv') - res = pd.read_csv(csvPath, skipinitialspace=True) - addAccumPseudoStep(res) - plotResiduals(res, resolution, naming2[j]) - axes[0].set_xlim([0,4000]) - figures[0].savefig(f'figures/Residuals_Adaptive_from_scratch.png', dpi=500); - -if __name__ == '__main__': - main() - diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py b/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py deleted file mode 100644 index 3f7c98f..0000000 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Download_Data.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -import flow360 as fl -from flow360 import MyCases - - -#read in caseNameList - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -my_cases = MyCases(limit=None) - -for i in range(0, len(caseNameList)): - caseFolder = os.path.join(os.getcwd(), caseNameList[i]) - os.makedirs(caseFolder, exist_ok = True) - #Find the latest case with the name corresponding to the name in caseNameList - for case in my_cases: - if case.name == caseNameList[i]: - break - print(case.name) - #Download the files - case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Files.py b/examples/Solver_Features/Adaptive_CFL/XV15/Files.py deleted file mode 100644 index 6f615c1..0000000 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Files.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from flow360.examples import base_test_case -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default = 0, type = int, required = False) -args = parser.parse_args() -local = args.localFiles - -base_test_case.here = os.path.dirname(os.path.abspath(__file__)) - -class XV15(base_test_case.BaseTestCase): - name = "localFiles" - if local==1: - class url: - mesh = "local://xv15_airplane_pitch26.cgns" - case_json = "local://Flow360.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Adaptive_CFL/XV15/xv15_airplane_pitch26.cgns.bz2" - case_json = "local://Flow360.json" - diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json similarity index 100% rename from examples/Solver_Features/Adaptive_CFL/XV15/localFiles/Flow360.json rename to examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json new file mode 100644 index 0000000..16e2eb1 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json @@ -0,0 +1,86 @@ +{ + "geometry": { + "refArea": 70685.83470577035, + "momentCenter": [ + 0, + 0, + 0 + ], + "momentLength": [ + 150, + 150, + 150 + ] + }, + "volumeOutput": { + "outputFormat": "paraview", + "outputFields" : ["primitiveVars", "qcriterion", "Mach"] + }, + "surfaceOutput": { + "outputFormat": "paraview", + "outputFields" : ["primitiveVars", "Cp", "Cf", "CfVec", "yPlus"] + }, + "navierStokesSolver": { + "absoluteTolerance": 1e-9, + "relativeTolerance": 0.01, + "linearIterations": 35, + "kappaMUSCL": -1, + "orderOfAccuracy": 1, + "updateJacobianFrequency": 1, + "equationEvalFrequency": 1 + }, + "turbulenceModelSolver": { + "modelType": "SpalartAllmaras", + "absoluteTolerance": 1e-8, + "relativeTolerance": 0.01, + "linearIterations": 35, + "DDES": true, + "orderOfAccuracy": 1, + "updateJacobianFrequency": 1, + "equationEvalFrequency": 1, + "rotationCorrection": true + }, + "freestream": { + "muRef": 0.00000168, + "Mach": 0.182, + "MachRef": 0.54, + "Temperature": 288.15, + "alphaAngle": -90, + "betaAngle": 0 + }, + "boundaries": { + "stationaryField/farfield": { + "type": "Freestream" + }, + "rotationField/blade": { + "type": "NoSlipWall" + }, + "rotationField/blade_2": { + "type": "NoSlipWall" + }, + "rotationField/blade_3": { + "type": "NoSlipWall" + } + }, + "volumeZones":{ + "rotationField":{ + "modelType": "FluidDynamics", + "referenceFrame":{ + "axisOfRotation" : [0,0,-1], + "centerOfRotation" : [0,0,0], + "omega" : 0.0036 + } + } + }, + "timeStepping": { + "timeStepSize": 29.08882086657216, + "physicalSteps": 120, + "maxPseudoSteps": 13, + "CFL": { + "type": "ramp", + "initial": 1, + "final": 1000, + "rampSteps": 11 + } + } +} diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/README.md b/examples/Solver_Features/Adaptive_CFL/XV15/README.md index a9943b4..40036c7 100644 --- a/examples/Solver_Features/Adaptive_CFL/XV15/README.md +++ b/examples/Solver_Features/Adaptive_CFL/XV15/README.md @@ -1,12 +1,9 @@ -To run the demo case follow these steps: - -1. Run Submit_Cases.py -> this script will obtain the mesh and submit ramp and adaptive CFL cases for the XV15 rotor. +The following example demonstrates the use of adaptive CFL for the XV15 rotor. -2. Run Download_Data.py -> this script will download the csv files containing the loads and residual histories. - -3. Run Convergence_Plots.py -> this script will cross-plot the residual convergence histories for the ramp and adaptive CFL cases forked from the 1st order solution and a clean 2nd order adpative CFL simulation. +To run the demo case follow these steps: -Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". -To run with a mesh stored in the "localFiles" directory, Run Submit_Cases.py --localFiles 1 +1. Run `python submit_cases_from_downloads.py` -> this script will download the XV15 rotor mesh, and upload it to the Flexcompute servers. The cases will also be submitted for both adaptive and ramp CFL. Alternatively the script `submit_cases_from_id.py` can also be used to run the cases from meshes 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 residual convergence histories for the ramp and adaptive CFL cases. diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py b/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py deleted file mode 100644 index 29ee8dc..0000000 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Submit_Cases.py +++ /dev/null @@ -1,63 +0,0 @@ -import flow360 as fl -from Files import XV15 - -print("Obtaining mesh and solver files") - -XV15.get_files() - -print("Files accessed") - -caseNameList=[] - -# submit mesh -volume_mesh = fl.VolumeMesh.from_file(XV15.mesh_filename, name="XV15_Mesh") -volume_mesh = volume_mesh.submit() - -#submit 1st order case -params = fl.Flow360Params(XV15.case_json) -case = fl.Case.create("XV15_1st_order_ramp", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -#update solver and time-stepping parameters -params.navier_stokes_solver.order_of_accuracy=2 -params.turbulence_model_solver.order_of_accuracy=2 - -params.time_stepping.max_pseudo_steps = 35 -params.time_stepping.time_step_size = 29.08882086657216 - -params.time_stepping.CFL.final = 1e7 -params.time_stepping.CFL.ramp_steps = 33 - - -#submit 2nd order ramp case (forked from first order) -case_fork_1 = case.fork() -case_fork_1.name = "XV15_2nd_order_ramp_forked" -caseNameList.append(case_fork_1.name) -case_fork_1.params = params -print(params) -case_fork_1 = case_fork_1.submit() - -#change CFL type to adaptive -params.time_stepping.CFL.type = "adaptive" - -#submit 2nd order adaptive case (forked from first order) -case_fork_2 = case.fork() -case_fork_2.name = "XV15_2nd_order_adaptive_forked" -caseNameList.append(case_fork_2.name) -case_fork_2.params = params -print(params) -case_fork_2 = case_fork_2.submit() - - -#submit adaptive CFL case -case = fl.Case.create("XV15_2nd_order_adaptive", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - - -# dump case names for use in download and post-processing scripts - -with open('caseNameList.dat', 'w') as f: - for line in caseNameList: - f.write(f"{line}\n") diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/convergence_plots.py b/examples/Solver_Features/Adaptive_CFL/XV15/convergence_plots.py new file mode 100644 index 0000000..5f322d2 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/convergence_plots.py @@ -0,0 +1,68 @@ +"""Plot the residuals convergence plots for the ramp and adaptive CFL 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() + +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_residuals(data, plot_name): + "Plot the residuals" + x = data["accum_pseudo_step"] + for ax, res in zip(axes, residuals): + for res in residuals: + if "ramp" in plot_name: + ax.semilogy(x, data[res], label=plot_name + " " + res) + else: + ax.semilogy(x, data[res], "--", label=plot_name + " " + res) + + ax.legend(loc="upper right") + ax.grid(which="major", color="gray") + ax.set_title("XV15 Rotor - Residuals") + ax.set_xlabel("Accumulated Pseudo step") + ax.set_yticks(10.0 ** np.arange(-11, -3)) + ax.set_ylim([1e-9, 1e-3]) + ax.set_xlim([3000, 4000]) + ax.set_ylabel("Residuals") + + +# set output directory +dir_path = os.path.join(os.getcwd(), "figures") +os.makedirs(dir_path, exist_ok=True) + +fig, ax = plt.subplots(figsize=(8, 6)) +figures.append(fig) +axes.append(ax) + +for case_name in case_name_list: + if "2nd_order" in case_name: + if "adaptive" 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) + add_accum_pseudo_step(data) + plot_residuals(data, case_name) +figures[0].savefig(os.path.join(dir_path, "residuals.png"), dpi=500) +axes[0].set_xlim([3450, 3550]) +figures[0].savefig("figures/residuals_zoomed.png", dpi=500) diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/download_data.py b/examples/Solver_Features/Adaptive_CFL/XV15/download_data.py new file mode 100644 index 0000000..749fef1 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/download_data.py @@ -0,0 +1,27 @@ +"""Download the results for the ramp and adaptive CFL cases at both angles of attack""" + +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/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_downloads.py b/examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_downloads.py new file mode 100644 index 0000000..999cea5 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_downloads.py @@ -0,0 +1,62 @@ +"""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 = "PLACEHOLDER" +MESH_FILENAME = "xv15_airplane_pitch26.cgns" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + + +# submit mesh +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="XV15_Mesh") +volume_mesh = volume_mesh.submit() + +params = fl.Flow360Params("Flow360.json") + +# submit 1st order case +case = fl.Case.create("XV15_1st_order_ramp", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# update solver and time-stepping parameters +params.navier_stokes_solver.order_of_accuracy = 2 +params.turbulence_model_solver.order_of_accuracy = 2 + +params.time_stepping.max_pseudo_steps = 35 +params.time_stepping.time_step_size = 29.08882086657216 + +params.time_stepping.CFL.final = 1e7 +params.time_stepping.CFL.ramp_steps = 33 + + +# submit 2nd order ramp case (forked from first order) +case_fork_1 = case.fork() +case_fork_1.name = "XV15_2nd_order_ramp" +case_name_list.append(case_fork_1.name) +case_fork_1.params = params +case_fork_1 = case_fork_1.submit() + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + + +# submit adaptive CFL case +case2 = fl.Case.create("XV15_2nd_order_adaptive", params, volume_mesh.id) +case_name_list.append(case2.name) +case2 = case2.submit() + + +# dump case names 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/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_id.py b/examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_id.py new file mode 100644 index 0000000..a4ed885 --- /dev/null +++ b/examples/Solver_Features/Adaptive_CFL/XV15/submit_cases_from_id.py @@ -0,0 +1,45 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID = "05f1b090-2e93-4032-b703-ca665c1f9700" + +# submit 1st order case +params = fl.Flow360Params("Flow360.json") +case = fl.Case.create("XV15_1st_order_ramp", params, MESH_ID) +case_name_list.append(case.name) +case = case.submit() + +# update solver and time-stepping parameters +params.navier_stokes_solver.order_of_accuracy = 2 +params.turbulence_model_solver.order_of_accuracy = 2 + +params.time_stepping.max_pseudo_steps = 35 +params.time_stepping.time_step_size = 29.08882086657216 + +params.time_stepping.CFL.final = 1e7 +params.time_stepping.CFL.ramp_steps = 33 + + +# submit 2nd order ramp case (forked from first order) +case_fork_1 = case.fork() +case_fork_1.name = "XV15_2nd_order_ramp" +case_name_list.append(case_fork_1.name) +case_fork_1.params = params +case_fork_1 = case_fork_1.submit() + +# change CFL type to adaptive +params.time_stepping.CFL.type = "adaptive" + +# submit adaptive CFL case +case2 = fl.Case.create("XV15_2nd_order_adaptive", params, MESH_ID) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case names 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/Solver_Features/Debug_Divergence/Download_Data.py b/examples/Solver_Features/Debug_Divergence/Download_Data.py deleted file mode 100644 index 6d9bf26..0000000 --- a/examples/Solver_Features/Debug_Divergence/Download_Data.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import flow360 as fl -from flow360 import MyCases - - -#read in caseNameList - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -my_cases = MyCases(limit=None) - -for i in range(0, len(caseNameList)): - caseFolder = os.path.join(os.getcwd(), caseNameList[i]) - os.makedirs(caseFolder, exist_ok = True) - #Find the latest case with the name corresponding to the name in caseNameList - for case in my_cases: - if case.name == caseNameList[i]: - break - print(case.name) - #Download the files - case.results.download(minmax_state=True, destination=caseFolder) - diff --git a/examples/Solver_Features/Debug_Divergence/Files.py b/examples/Solver_Features/Debug_Divergence/Files.py deleted file mode 100644 index 8bf6af7..0000000 --- a/examples/Solver_Features/Debug_Divergence/Files.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -from flow360.examples import base_test_case -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default = 0, type = int, required = False) -args = parser.parse_args() -local = args.localFiles - -base_test_case.here = os.path.dirname(os.path.abspath(__file__)) - -class CRM_PoorSurface(base_test_case.BaseTestCase): - name = "localFiles" - if local==1: - class url: - mesh = "local://Unswept_CRM_Poor_Surface.cgns" - case_json = "local://Flow360_PoorSurface.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Mesh_Metrics/Unswept_CRM_Poor_Surface.cgns.bz2" - case_json = "local://Flow360_PoorSurface.json" - -class CRM_AD(base_test_case.BaseTestCase): - name = "localFiles" - if local==1: - class url: - mesh = "local://Unswept_CRM_AD.cgns" - case_json = "local://Flow360_AD.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Debug_Divergence/Unswept_CRM_AD.cgns.bz2" - case_json = "local://Flow360_AD.json" - diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json b/examples/Solver_Features/Debug_Divergence/Flow360_AD.json similarity index 100% rename from examples/Solver_Features/Debug_Divergence/localFiles/Flow360_AD.json rename to examples/Solver_Features/Debug_Divergence/Flow360_AD.json diff --git a/examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json b/examples/Solver_Features/Debug_Divergence/Flow360_PoorSurface.json similarity index 100% rename from examples/Solver_Features/Debug_Divergence/localFiles/Flow360_PoorSurface.json rename to examples/Solver_Features/Debug_Divergence/Flow360_PoorSurface.json diff --git a/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py b/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py deleted file mode 100644 index 873f80a..0000000 --- a/examples/Solver_Features/Debug_Divergence/Print_Divergence_Locations.py +++ /dev/null @@ -1,27 +0,0 @@ -import matplotlib.pyplot as plt -from collections import defaultdict -import os, csv -import numpy as np -import pandas as pd - - - - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -for resolution in caseNameList: - csvPath = os.path.join(os.getcwd(),f'{resolution}','minmax_state_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - print(resolution) - print("Minimum Density: " + str(data[f"min_rho"][len(data)-1])+" at location (x="+ str(data[f"min_rho_x"][len(data)-1])+ ", y=" + str(data[f"min_rho_y"][len(data)-1])+", z="+ str(data[f"min_rho_z"][len(data)-1]) +")" ) - print("Minimum Pressure: " + str(data[f"min_p"][len(data)-1])+" at location (x="+ str(data[f"min_p_x"][len(data)-1])+ ", y=" + str(data[f"min_p_y"][len(data)-1])+", z="+ str(data[f"min_p_z"][len(data)-1]) +")" ) - print("Maximum Velocity Magnitude: " + str(data[f"max_umag"][len(data)-1])+" at location (x="+ str(data[f"max_umag_x"][len(data)-1])+ ", y=" + str(data[f"max_umag_y"][len(data)-1])+", z="+ str(data[f"max_umag_z"][len(data)-1]) +")" ) - print("Minimum nuHat Magnitude: " + str(data[f"min_nuHat"][len(data)-1])+" at location (x="+ str(data[f"min_nuHat_x"][len(data)-1])+ ", y=" + str(data[f"min_nuHat_y"][len(data)-1])+", z="+ str(data[f"min_nuHat_z"][len(data)-1]) +")" ) - - - - - - - diff --git a/examples/Solver_Features/Debug_Divergence/README b/examples/Solver_Features/Debug_Divergence/README.md similarity index 51% rename from examples/Solver_Features/Debug_Divergence/README rename to examples/Solver_Features/Debug_Divergence/README.md index e6413c1..fd5faf0 100644 --- a/examples/Solver_Features/Debug_Divergence/README +++ b/examples/Solver_Features/Debug_Divergence/README.md @@ -1,10 +1,12 @@ The following cases are for a demonstration of the debug divergence pipeline and are intended to diverge. -1. Run Submit_Cases.py -> this script will obtain the meshes, and upload them to the Flexcompute servers. The cases will also be submitted. +To run the demo case follow these steps: -2. Run Download_Data.py -> this script will download the csv files containing the min/max locations of the pressure, density, velocity magnitude and turbulent variables. +1. Run `python submit_cases_from_downloads.py` -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. Alternatively the script `submit_cases_from_id.py` can also be used to run the cases from meshes already uploaded to Flexcompute servers. -3. Run Print_Divergence_Locations.py -> this script will print the minimum pressure, minimum density, maxiumum velocity magnitude and minimum nuHat at the last iteration. +2. Run `python download_data.py` -> this script will download the csv files containing the min/max locations of the pressure, density, velocity magnitude and turbulent variables. + +3. Run `python print_divergence_locations.py` -> this script will print the minimum pressure, minimum density, maxiumum velocity magnitude and minimum nuHat at the last iteration. 4. Investigate the mesh at the location, where one of the variables went non-physical (e.g. negative pressure or density) diff --git a/examples/Solver_Features/Debug_Divergence/Submit_Cases.py b/examples/Solver_Features/Debug_Divergence/Submit_Cases.py deleted file mode 100644 index 05394b6..0000000 --- a/examples/Solver_Features/Debug_Divergence/Submit_Cases.py +++ /dev/null @@ -1,37 +0,0 @@ -import flow360 as fl -from Files import CRM_PoorSurface, CRM_AD - -print("Obtaining mesh and solver files") - -CRM_PoorSurface.get_files() -CRM_AD.get_files() - -print("Files accessed") - -caseNameList=[] - -# submit mesh with poor surface -volume_mesh = fl.VolumeMesh.from_file(CRM_PoorSurface.mesh_filename, name="CRM_Poor_Surface_Mesh") -volume_mesh = volume_mesh.submit() - -#submit case with poor surface -params = fl.Flow360Params(CRM_PoorSurface.case_json) -case = fl.Case.create("CRM_Poor_Surface", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -# submit mesh with actuator disk -volume_mesh = fl.VolumeMesh.from_file(CRM_AD.mesh_filename, name="CRM_AD_Mesh") -volume_mesh = volume_mesh.submit() - -#submit case with actuator disk -params = fl.Flow360Params(CRM_AD.case_json) -case = fl.Case.create("CRM_AD", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -# dump case names for use in download and post-processing scripts - -with open('caseNameList.dat', 'w') as f: - for line in caseNameList: - f.write(f"{line}\n") diff --git a/examples/Solver_Features/Debug_Divergence/download_data.py b/examples/Solver_Features/Debug_Divergence/download_data.py new file mode 100644 index 0000000..ce6775b --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/download_data.py @@ -0,0 +1,27 @@ +"""Download the min/max locations for the poor surface mesh CRM and actuator disk cases""" + +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( + minmax_state=True, + destination=case_folder, + ) diff --git a/examples/Solver_Features/Debug_Divergence/print_divergence_locations.py b/examples/Solver_Features/Debug_Divergence/print_divergence_locations.py new file mode 100644 index 0000000..8eaa02a --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/print_divergence_locations.py @@ -0,0 +1,45 @@ +"""Print the divergence locations for minimum density, pressure, eddy viscosity and maximum velocity magnitude""" + +import os + +import pandas as pd + +with open("case_name_list.dat", "r", encoding="utf-8") as file: + case_name_list = file.read().splitlines() + +for case in case_name_list: + csv_path = os.path.join(os.getcwd(), case, "minmax_state_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + print(case) + print( + "Minimum Density:{} at location xyz = {}, {}, {}".format( + data["min_rho"].values[-1], + data["min_rho_x"].values[-1], + data["min_rho_y"].values[-1], + data["min_rho_z"].values[-1], + ) + ) + print( + "Minimum Pressure: {} at location xyz = {}, {}, {}".format( + data["min_p"].values[-1], + data["min_p_x"].values[-1], + data["min_p_y"].values[-1], + data["min_p_z"].values[-1], + ) + ) + print( + "Maximum Velocity Magnitude: {} at location xyz = {}, {}, {}".format( + data["max_umag"].values[-1], + data["max_umag_x"].values[-1], + data["max_umag_y"].values[-1], + data["max_umag_z"].values[-1], + ) + ) + print( + "Minimum nuHat Magnitude: {} at location xyz = {}, {}, {}".format( + data["min_nuHat"].values[-1], + data["min_nuHat_x"].values[-1], + data["min_nuHat_y"].values[-1], + data["min_nuHat_z"].values[-1], + ) + ) diff --git a/examples/Solver_Features/Debug_Divergence/submit_cases_from_downloads.py b/examples/Solver_Features/Debug_Divergence/submit_cases_from_downloads.py new file mode 100644 index 0000000..c2f64c6 --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/submit_cases_from_downloads.py @@ -0,0 +1,48 @@ +"""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 = "PLACEHOLDER" +MESH_FILENAME = "Unswept_CRM_Poor_Surface.cgns" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + +URL2 = "PLACEHOLDER" +MESH_FILENAME2 = "Unswept_CRM_AD.cgns" + +if not os.path.isfile(MESH_FILENAME2): + urlretrieve(URL2, MESH_FILENAME2) + +# submit mesh with poor surface +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="CRM_Poor_Surface_Mesh") +volume_mesh = volume_mesh.submit() + +# submit mesh with actuator disk +volume_mesh2 = fl.VolumeMesh.from_file(MESH_FILENAME2, name="CRM_AD_Mesh") +volume_mesh2 = volume_mesh2.submit() + +# submit case with poor surface +params = fl.Flow360Params("Flow360_PoorSurface.json") +case = fl.Case.create("CRM_Poor_Surface", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# submit case with actuator disk +params2 = fl.Flow360Params("Flow360_AD.json") +case2 = fl.Case.create("CRM_AD", params2, volume_mesh2.id) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case names 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/Solver_Features/Debug_Divergence/submit_cases_from_id.py b/examples/Solver_Features/Debug_Divergence/submit_cases_from_id.py new file mode 100644 index 0000000..e7bf7bd --- /dev/null +++ b/examples/Solver_Features/Debug_Divergence/submit_cases_from_id.py @@ -0,0 +1,25 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID = "49d4b0aa-3a42-4879-8c9c-d977112e7665" +MESH_ID2 = "2c1fb0cb-36bc-47f9-a166-4a61507ebfc8" + +# submit case with poor surface +params = fl.Flow360Params("Flow360_PoorSurface.json") +case = fl.Case.create("CRM_Poor_Surface", params, MESH_ID) +case_name_list.append(case.name) +case = case.submit() + +# submit case with actuator disk +params2 = fl.Flow360Params("Flow360_AD.json") +case2 = fl.Case.create("CRM_AD", params2, MESH_ID2) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case names 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/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py b/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py deleted file mode 100644 index 47520f0..0000000 --- a/examples/Solver_Features/Mesh_Metrics/Download_MeshMetrics.py +++ /dev/null @@ -1,20 +0,0 @@ -import flow360 as fl -from Files import CRM_PoorSurface - -print("Obtaining mesh and solver files") - -CRM_PoorSurface.get_files() - -print("Files accessed") - -with open('meshNameList.dat', 'r') as file: - meshNameList = file.read().splitlines() - - -my_meshes= fl.MyVolumeMeshes(limit=None) -for i in range(0, len(meshNameList)): - for mesh in my_meshes: - if mesh.name == meshNameList[i]: - break -print(mesh.name) -mesh.download_file("metadata/meshMetrics.json", to_folder="./") diff --git a/examples/Solver_Features/Mesh_Metrics/Files.py b/examples/Solver_Features/Mesh_Metrics/Files.py deleted file mode 100644 index 67dd9d9..0000000 --- a/examples/Solver_Features/Mesh_Metrics/Files.py +++ /dev/null @@ -1,22 +0,0 @@ -import os -from flow360.examples import base_test_case -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default = 0, type = int, required = False) -args = parser.parse_args() -local = args.localFiles - -base_test_case.here = os.path.dirname(os.path.abspath(__file__)) - -class CRM_PoorSurface(base_test_case.BaseTestCase): - name = "localFiles" - if local==1: - class url: - mesh = "local://Unswept_CRM_Poor_Surface.cgns" - case_json = "local://Flow360_PoorSurface.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/examples/Solver_Features/Mesh_Metrics/Unswept_CRM_Poor_Surface.cgns.bz2" - case_json = "local://Flow360_PoorSurface.json" - diff --git a/examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json b/examples/Solver_Features/Mesh_Metrics/Flow360_PoorSurface.json similarity index 100% rename from examples/Solver_Features/Mesh_Metrics/localFiles/Flow360_PoorSurface.json rename to examples/Solver_Features/Mesh_Metrics/Flow360_PoorSurface.json diff --git a/examples/Solver_Features/Mesh_Metrics/README.md b/examples/Solver_Features/Mesh_Metrics/README.md index 7cab3a4..ae982aa 100644 --- a/examples/Solver_Features/Mesh_Metrics/README.md +++ b/examples/Solver_Features/Mesh_Metrics/README.md @@ -1,11 +1,7 @@ -To run the demo case follow these steps: +This following example demonstrates the mesh metrics feature for a poor mesh of the unswept CRM wing. -1. Run Submit_Mesh.py -> this script will upload the mesh to the Flexcompute servers +To run the demo case perform one of the following steps: -2. Note that the mesh metrics take a short amount of time to be calculated once the mesh is uploaded. To check whether the mesh metrics have been calculated, try downloading the meshMetrics.json file using Download_MeshMetrics.py - -3. Run Submit_Case.py -> this script will upload the case with a poor surface mesh, which will trigger mesh metrics validation warnings. - -Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". -To run with a mesh stored in the "localFiles" directory, Run SubmitMesh.py or Submit_Cases.py --localFiles 1 +If the mesh is already uploaded on the flexcompute servers, run `python submit_case_from_mesh_id.py` -> this script will upload the case with a poor surface mesh, which will trigger mesh metrics validation warnings. +Alternatively, the mesh can be uploaded using `python submit_mesh_from_download.py`. The case can then be uploaded using `python submit_case_from_mesh_name` Note that the mesh metrics can take a short amount of time to be calculated, once the mesh is uploaded. To check whether the mesh metrics are available, the following script can be ran: `python download_mesh_metrics`. diff --git a/examples/Solver_Features/Mesh_Metrics/Submit_Case.py b/examples/Solver_Features/Mesh_Metrics/Submit_Case.py deleted file mode 100644 index f0e249b..0000000 --- a/examples/Solver_Features/Mesh_Metrics/Submit_Case.py +++ /dev/null @@ -1,24 +0,0 @@ -import flow360 as fl -from Files import CRM_PoorSurface - -print("Obtaining mesh and solver files") - -CRM_PoorSurface.get_files() - -print("Files accessed") - -with open('meshNameList.dat', 'r') as file: - meshNameList = file.read().splitlines() - - -my_meshes= fl.MyVolumeMeshes() -for i in range(0, len(meshNameList)): - for mesh in my_meshes: - if mesh.name == meshNameList[i]: - break - - -#submit case with poor surface - params = fl.Flow360Params(CRM_PoorSurface.case_json) - case = fl.Case.create("CRM_Poor_Surface", params, mesh.id) - case = case.submit() diff --git a/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py b/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py deleted file mode 100644 index 0959924..0000000 --- a/examples/Solver_Features/Mesh_Metrics/Submit_Mesh.py +++ /dev/null @@ -1,19 +0,0 @@ -import flow360 as fl -from Files import CRM_PoorSurface - -print("Obtaining mesh and solver files") - -CRM_PoorSurface.get_files() - -print("Files accessed") - -meshNameList=[] - -# submit mesh with poor surface -volume_mesh = fl.VolumeMesh.from_file(CRM_PoorSurface.mesh_filename, name="CRM_Poor_Surface_Mesh") -volume_mesh = volume_mesh.submit() -meshNameList.append(volume_mesh.name) - -with open('meshNameList.dat', 'w') as f: - for line in meshNameList: - f.write(f"{line}\n") diff --git a/examples/Solver_Features/Mesh_Metrics/download_mesh_metrics.py b/examples/Solver_Features/Mesh_Metrics/download_mesh_metrics.py new file mode 100644 index 0000000..1be929c --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/download_mesh_metrics.py @@ -0,0 +1,16 @@ +"""Downloads the mesh metrics to verify that they have been calculated after mesh upload""" + +import flow360 as fl + +with open("mesh_name_list.dat", "r", encoding="utf-8") as file: + mesh_name_list = file.read().splitlines() + +mesh = None + +my_meshes = fl.MyVolumeMeshes(limit=None) +for mesh_name in mesh_name_list: + for mesh in my_meshes: + if mesh.name == mesh_name: + break + +mesh.download_file("metadata/meshMetrics.json", to_folder="./") diff --git a/examples/Solver_Features/Mesh_Metrics/meshMetrics.json b/examples/Solver_Features/Mesh_Metrics/meshMetrics.json new file mode 100644 index 0000000..995494c --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/meshMetrics.json @@ -0,0 +1,317 @@ +{ + "boundaries": [ + { + "area": { + "arithmeticMean": 291.92082281439565, + "max": 473.2736511230469, + "maxElementTypes": "Triangle", + "maxLocation": [ + 147.55576534354338, + 173.443682294482, + 101.35589838513086 + ], + "min": 132.748291015625, + "minElementTypes": "Triangle", + "minLocation": [ + 63.28409037995478, + 226.93446344287602, + -82.99685725903372 + ] + }, + "areaRatio": { + "arithmeticMean": 1.4985113090976945, + "max": 2.681257724761963, + "maxElementTypes": [ + "Triangle", + "Triangle" + ], + "maxLocation": [ + [ + 41.22672636048258, + 235.12222480709738, + -72.30697082376679 + ], + [ + 63.28409037995478, + 226.93446344287602, + -82.99685725903372 + ] + ], + "min": 1.0005501508712769, + "minElementTypes": [ + "Triangle", + "Triangle" + ], + "minLocation": [ + [ + -216.8532168881018, + 5.701608820427729, + 123.08810546996047 + ], + [ + -206.0711587802807, + 5.701608820427729, + 140.50172722057076 + ] + ] + }, + "aspectRatio": { + "arithmeticMean": 1.2360145225757426, + "max": 2.1813117475558967, + "maxElementTypes": "Triangle", + "maxLocation": [ + 157.29089552318047, + 149.3299566269409, + 123.1598738884641 + ], + "min": 1.002476929672776, + "minElementTypes": "Triangle", + "minLocation": [ + -209.12872863786876, + 87.0875263617167, + 104.67364276064143 + ] + }, + "boundaryName": "fluid/farfield", + "firstLayerThickness": { + "arithmeticMean": 19.462266130911928, + "max": 30.74910545349121, + "maxElementTypes": "Node", + "maxLocation": [ + 20.125249633278905, + 248.82412762548896, + 13.473226733512927 + ], + "min": 9.850659370422363, + "minElementTypes": "Node", + "minLocation": [ + 77.96281986731935, + 64.44705885200133, + 228.62277953795996 + ] + }, + "nodeCount": 698 + }, + { + "area": { + "arithmeticMean": 1.945036356115944, + "max": 445.40167236328125, + "maxElementTypes": "Triangle", + "maxLocation": [ + 149.48777645821437, + 0.0, + 176.5591785237306 + ], + "min": 3.0505323744475787e-13, + "minElementTypes": "Triangle", + "minLocation": [ + 1.000000608340996, + 0.0, + 0.0014703500674634617 + ] + }, + "areaRatio": { + "arithmeticMean": 2.167965960269024, + "max": 7451.1826171875, + "maxElementTypes": [ + "Quadrilateral", + "Triangle" + ], + "maxLocation": [ + [ + 0.9991196802950424, + 0.0, + 0.0019439293803997222 + ], + [ + 1.000000608340996, + 0.0, + 0.0014703500674634617 + ] + ], + "min": 1.0005085468292236, + "minElementTypes": [ + "Quadrilateral", + "Quadrilateral" + ], + "minLocation": [ + [ + 0.9949392997459301, + 0.0, + 0.0004061822794153316 + ], + [ + 0.9930284808138277, + 0.0, + 0.0009942629024474203 + ] + ] + }, + "aspectRatio": { + "arithmeticMean": 155.74056106968388, + "max": 9645.000651435734, + "maxElementTypes": "Quadrilateral", + "maxLocation": [ + 0.0017712367717225902, + 0.0, + 0.004573968435596714 + ], + "min": 1.0013615647691088, + "minElementTypes": "Triangle", + "minLocation": [ + 1.332686192522447, + 0.0, + -0.09446793669282744 + ] + }, + "boundaryName": "fluid/symmetric", + "firstLayerThickness": { + "arithmeticMean": 0.20590281270261715, + "max": 23.850631713867188, + "maxElementTypes": "Node", + "maxLocation": [ + -238.23550010678917, + 0.0, + -75.7881685282609 + ], + "min": 4.633235221263021e-05, + "minElementTypes": "Node", + "minLocation": [ + -0.0007234002335295815, + 0.0, + -0.00033018886195446503 + ] + }, + "nodeCount": 73383 + }, + { + "area": { + "arithmeticMean": 0.00016775446368517011, + "max": 0.01729346439242363, + "maxElementTypes": "Quadrilateral", + "maxLocation": [ + 0.524345493855963, + 2.2948648494290977, + 0.06395318305183383 + ], + "min": 5.556775040105322e-09, + "minElementTypes": "Triangle", + "minLocation": [ + 0.0001067611691790419, + 4.999999999999999, + -0.00017025561013887778 + ] + }, + "areaRatio": { + "arithmeticMean": 2.6092350756744613, + "max": 16650.416015625, + "maxElementTypes": [ + "Triangle", + "Triangle" + ], + "maxLocation": [ + [ + 0.0012227912585606909, + 4.9799999999999995, + 0.003100949926446326 + ], + [ + 0.00012051441305754237, + 5.0, + -4.032887514092763e-06 + ] + ], + "min": 1.0, + "minElementTypes": [ + "Triangle", + "Triangle" + ], + "minLocation": [ + [ + 1.0, + 0.026248096390986523, + -0.00098 + ], + [ + 1.0, + 0.026248096390986523, + -0.00098 + ] + ] + }, + "aspectRatio": { + "arithmeticMean": 15.835971698502322, + "max": 3234.080179288396, + "maxElementTypes": "Quadrilateral", + "maxLocation": [ + 1.358701330455523e-06, + 2.294864849429104, + -2.4963051225807055e-05 + ], + "min": 1.0000652114477049, + "minElementTypes": "Triangle", + "minLocation": [ + 0.5409056017557239, + 0.0005078719426672653, + -0.0418308773330812 + ] + }, + "boundaryName": "fluid/wing", + "firstLayerThickness": { + "arithmeticMean": 9.94855714014816e-07, + "max": 1.0125497738044942e-06, + "maxElementTypes": "Node", + "maxLocation": [ + 0.9987884202543752, + 0.001092672346567293, + -0.0009659299906853389 + ], + "min": 9.339078399506207e-10, + "minElementTypes": "Node", + "minLocation": [ + 0.8860456275429734, + 4.992741128205036, + 0.028779738821366026 + ] + }, + "nodeCount": 34996 + } + ], + "version": "v1.0.0", + "volumetric": { + "aspectRatio": { + "arithmeticMean": 1514.9884540743383, + "max": 193869.71426557042, + "maxElementTypes": "Hexahedron", + "maxLocation": [ + 0.5243455076566441, + 2.294864849431958, + 0.06395368276418312 + ], + "min": 1.0350238270624377, + "minElementTypes": "Tetrahedron", + "minLocation": [ + 1.0387296013781655, + 5.056439364641543, + -0.03925651985503204 + ] + }, + "volume": { + "arithmeticMean": 6.561119480285893, + "max": 7237.24589751225, + "maxElementTypes": "Tetrahedron", + "maxLocation": [ + -17.706885592654487, + 175.4454219756072, + -92.69272185260752 + ], + "min": 7.638792269195606e-19, + "minElementTypes": "Prism", + "minLocation": [ + 1.0000011401438824, + 5.00000034892017, + 0.0014706859379563682 + ] + } + } +} diff --git a/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_id.py b/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_id.py new file mode 100644 index 0000000..1e73163 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_id.py @@ -0,0 +1,21 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +mesh_name_list = [] + +MESH_ID = "49d4b0aa-3a42-4879-8c9c-d977112e7665" + +# submit case with poor surface +params = fl.Flow360Params("CRM_PoorSurface.json") +case = fl.Case.create("CRM_Poor_Surface", params, MESH_ID) +case = case.submit() + +# write the volume mesh name to a file +volume_mesh = fl.VolumeMesh(MESH_ID) + +mesh_name_list.append(volume_mesh.name) + +with open("mesh_name_list.dat", "w", encoding="utf-8") as f: + for line in mesh_name_list: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_name.py b/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_name.py new file mode 100644 index 0000000..bdc3391 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/submit_case_from_mesh_name.py @@ -0,0 +1,18 @@ +"""Case submission from mesh name stored in mesh_name_list.dat""" + +import flow360 as fl + +with open("mesh_name_list.dat", "r", encoding="utf=8") as file: + mesh_name_list = file.read().splitlines() + +mesh = None +my_meshes = fl.MyVolumeMeshes(limit=None) +for mesh_name in mesh_name_list: + for mesh in my_meshes: + if mesh.name == mesh_name: + break + + # submit case with poor surface + params = fl.Flow360Params("Flow360_PoorSurface.json") + case = fl.Case.create("CRM_Poor_Surface", params, mesh.id) + case = case.submit() diff --git a/examples/Solver_Features/Mesh_Metrics/submit_mesh_from_download.py b/examples/Solver_Features/Mesh_Metrics/submit_mesh_from_download.py new file mode 100644 index 0000000..e3d7139 --- /dev/null +++ b/examples/Solver_Features/Mesh_Metrics/submit_mesh_from_download.py @@ -0,0 +1,26 @@ +"""Submits the mesh from mesh download and upload onto Flexcompute servers""" + +import os.path +from urllib.request import urlretrieve + +import flow360 as fl + +mesh_name_list = [] + +# download meshes to the current directory + +URL = "PLACEHOLDER" +MESH_FILENAME = "Unswept_CRM_Poor_Surface.cgns" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + + +# submit mesh with poor surface +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="CRM_Poor_Surface_Mesh") +volume_mesh = volume_mesh.submit() +mesh_name_list.append(volume_mesh.name) + +with open("mesh_name_list.dat", "w", encoding="utf-8") as f: + for line in mesh_name_list: + f.write(f"{line}\n") diff --git a/examples/Solver_Features/Wall_Model/Convergence_Plots.py b/examples/Solver_Features/Wall_Model/Convergence_Plots.py deleted file mode 100644 index 04f198d..0000000 --- a/examples/Solver_Features/Wall_Model/Convergence_Plots.py +++ /dev/null @@ -1,89 +0,0 @@ -import matplotlib.pyplot as plt -from collections import defaultdict -import os, csv -import numpy as np -import pandas as pd - -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -loads = ['CL', 'CD'] -residuals = ['0_cont', '1_momx', '2_momy', '3_momz', '4_energ', '5_nuHat'] -figures = [] -axes = [] - - -def computeCLCD(data): - CL0 = np.add(data['Windsor_CL'], data['Windsor_rear_CL']) - data['CL'] = np.add(data['Windsor_supports_CL'], CL0) - CD0 = np.add(data['Windsor_CD'], data['Windsor_rear_CD']) - data['CD'] = np.add(data['Windsor_supports_CD'], CD0) - - -def plotLoads(data, plotName): - x = data['pseudo_step'] - for ax, load in zip(axes, loads): - ax.plot(x, data[load], label=plotName) - ax.set_ylabel(load) - ax.legend() - ax.set_xlabel('Pseudo step') - ax.grid(which='major', color='gray') - if load == 'CL': - ax.set_ylim(-0.2, -0.1) - elif load == 'CD': - ax.set_ylim(0.25, 0.45) - - -def plotResiduals(data, plotName): - x = data['pseudo_step'] - for ax, res in zip(axes, residuals): - ax.semilogy(x, data[res], label=plotName) - ax.set_ylabel(res) - ax.legend() - ax.grid(which='major', color='gray') - ax.set_xlabel('Pseudo step') - ax.set_yticks(10.0**np.arange(-14, -3)) - ax.set_ylim([1e-13, 1e-3]) - ax.set_xlim([0, 10000]) - - -def main(): - # 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 caseName in caseNameList: - csvPath = os.path.join(os.getcwd(), caseName, 'surface_forces_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - computeCLCD(data) - plotLoads(data, caseName) - - # save loads figures - 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 - for res in residuals: - fig, ax = plt.subplots(figsize=(8, 6)) - figures.append(fig) - axes.append(ax) - for caseName in caseNameList: - csvPath = os.path.join(os.getcwd(), caseName, 'nonlinear_residual_v2.csv') - data = pd.read_csv(csvPath, skipinitialspace=True) - plotResiduals(data, caseName) - for i, res in enumerate(residuals): - figures[i].savefig(os.path.join(dir_path, res + '.png'), dpi=500) - - -if __name__ == '__main__': - main() diff --git a/examples/Solver_Features/Wall_Model/Download_Data.py b/examples/Solver_Features/Wall_Model/Download_Data.py deleted file mode 100644 index 2dceeb7..0000000 --- a/examples/Solver_Features/Wall_Model/Download_Data.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import flow360 as fl -from flow360 import MyCases - -# read in caseNameList -with open('caseNameList.dat', 'r') as file: - caseNameList = file.read().splitlines() - -# get case list from Flow360 -my_cases = MyCases(limit=None) - -for caseName in caseNameList: - caseFolder = os.path.join(os.getcwd(), caseName) - os.makedirs(caseFolder, exist_ok=True) - # find the latest case with name corresponding to caseNameList - for case in my_cases: - if case.name == caseName: - break - print(case.name) - # download the files - case.results.download(nonlinear_residuals=True, surface_forces=True, total_forces=True, destination=caseFolder) diff --git a/examples/Solver_Features/Wall_Model/Files.py b/examples/Solver_Features/Wall_Model/Files.py deleted file mode 100644 index 365daf9..0000000 --- a/examples/Solver_Features/Wall_Model/Files.py +++ /dev/null @@ -1,32 +0,0 @@ -import os -from flow360.examples import base_test_case -import argparse - -parser = argparse.ArgumentParser() -parser.add_argument('--localFiles', default=0, type=int, required=False) -args = parser.parse_args() -local = args.localFiles - -base_test_case.here = os.path.dirname(os.path.abspath(__file__)) - -class WallResolved(base_test_case.BaseTestCase): - name = "localFiles" - - if local == 1: - class url: - mesh = "local://Windsor_Wall_Resolved_1e-06.b8.ugrid" - case_json = "local://Flow360.json" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Resolved_1e-06.b8.ugrid" - case_json = "local://Flow360.json" - -class WallModel(base_test_case.BaseTestCase): - name = "localFiles" - - if local == 1: - class url: - mesh = "local://Windsor_Wall_Model_5e-04.b8.ugrid" - else: - class url: - mesh = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Model_5e-04.b8.ugrid" diff --git a/examples/Solver_Features/Wall_Model/localFiles/Flow360.json b/examples/Solver_Features/Wall_Model/Flow360.json similarity index 100% rename from examples/Solver_Features/Wall_Model/localFiles/Flow360.json rename to examples/Solver_Features/Wall_Model/Flow360.json diff --git a/examples/Solver_Features/Wall_Model/README.md b/examples/Solver_Features/Wall_Model/README.md index ac3316d..19ee98b 100644 --- a/examples/Solver_Features/Wall_Model/README.md +++ b/examples/Solver_Features/Wall_Model/README.md @@ -1,12 +1,13 @@ +The following example compares wall-resolved and wall-modeled simulations for the Windsor body. + To run the demo case follow these steps: -1. Run `python Submit_Cases.py` -> this script will download[^1] both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. +1. Run `python submit_cases_from_downloads.py` -> this script will download both wall resolved and wall model meshes, and upload them to the Flexcompute servers. The cases will also be submitted. Alternatively the script `submit_cases_from_id.py` can also be used to run the cases from meshes already uploaded to Flexcompute servers. -2. Run `python Download_Data.py` -> this script will download the csv files containing the loads and residual histories. +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 cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. +3. Run `python convergence_plots.py` -> this script will cross-plot the load and residual convergence histories for the wall-resolved and wall-modeled cases. -[^1] Files.py contains reference to the location of the meshes and JSON files. The default option is to use a mesh from Flexcompute storage servers and the Flow360.json file located in the "localFiles directory". To run with a mesh stored in the "localFiles" directory, run `python Submit_Cases.py --localFiles 1`. diff --git a/examples/Solver_Features/Wall_Model/Submit_Cases.py b/examples/Solver_Features/Wall_Model/Submit_Cases.py deleted file mode 100644 index 557a68e..0000000 --- a/examples/Solver_Features/Wall_Model/Submit_Cases.py +++ /dev/null @@ -1,43 +0,0 @@ -import os -import flow360 as fl -from Files import WallResolved, WallModel - -print("Obtaining mesh and solver files") -WallResolved.get_files() -WallModel.get_files() - -print("Files accessed") - -caseNameList = [] - -# submit wall resolved mesh -volume_mesh = fl.VolumeMesh.from_file(WallResolved.mesh_filename, name="Windsor_Wall_Resolved_Mesh") -volume_mesh = volume_mesh.submit() - -# submit wall model mesh -volume_mesh2 = fl.VolumeMesh.from_file(WallModel.mesh_filename, name="Windsor_Wall_Modeled_Mesh") -volume_mesh2 = volume_mesh2.submit() - -# submit wall-resolved case using json file -params = fl.Flow360Params(WallResolved.case_json) -case = fl.Case.create("Windsor_Wall_Resolved", params, volume_mesh.id) -caseNameList.append(case.name) -case = case.submit() - -# change NoSlipWall to WallFunction in params -Boundaries = params.boundaries -params.boundaries = Boundaries.copy(update={"1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), - "4": fl.WallFunction(name="Flow.CFDWT.Floor"), - "8": fl.WallFunction(name="Windsor"), - "9": fl.WallFunction(name="Windsor_rear"), - "10": fl.WallFunction(name="Windsor_supports")}) - -# submit wall-modeled case using updated parameters -case2 = fl.Case.create("Windsor_Wall_Modeled", params, volume_mesh2.id) -caseNameList.append(case2.name) -case2 = case2.submit() - -# dump case names for use in download and post-processing scripts -with open('caseNameList.dat', 'w') as f: - for line in caseNameList: - f.write(f"{line}\n") diff --git a/examples/Solver_Features/Wall_Model/convergence_plots.py b/examples/Solver_Features/Wall_Model/convergence_plots.py new file mode 100644 index 0000000..f110a8a --- /dev/null +++ b/examples/Solver_Features/Wall_Model/convergence_plots.py @@ -0,0 +1,94 @@ +"""Plot the loads and residuals convergence plots for the wall-resolved and wall-modeled 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 compute_cl_cd(data): + """Compute the Windsor body lift and drag from surface forces""" + + cl_0 = np.add(data["Windsor_CL"], data["Windsor_rear_CL"]) + data["CL"] = np.add(data["Windsor_supports_CL"], cl_0) + cd_0 = np.add(data["Windsor_CD"], data["Windsor_rear_CD"]) + data["CD"] = np.add(data["Windsor_supports_CD"], cd_0) + + +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.2, -0.1) + elif load == "CD": + ax.set_ylim(0.25, 0.45) + + +def plot_residuals(data, plot_name): + """Plot the residuals""" + + x = data["pseudo_step"] + for ax, res in zip(axes, residuals): + ax.semilogy(x, data[res], label=plot_name) + ax.set_ylabel(res) + ax.legend() + ax.grid(which="major", color="gray") + ax.set_xlabel("Pseudo step") + ax.set_yticks(10.0 ** np.arange(-14, -3)) + ax.set_ylim([1e-13, 1e-3]) + ax.set_xlim([0, 10000]) + + +# 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}", "surface_forces_v2.csv") + data = pd.read_csv(csv_path, skipinitialspace=True) + compute_cl_cd(data) + plot_loads(data, case_name) + +# save loads figures +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 +for res in residuals: + 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) +for i, res in enumerate(residuals): + figures[i].savefig(os.path.join(dir_path, res + ".png"), dpi=500) diff --git a/examples/Solver_Features/Wall_Model/download_data.py b/examples/Solver_Features/Wall_Model/download_data.py new file mode 100644 index 0000000..e7e25a9 --- /dev/null +++ b/examples/Solver_Features/Wall_Model/download_data.py @@ -0,0 +1,29 @@ +"""Download the results for the wall-resolved and wall-modeled cases""" + +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/Solver_Features/Wall_Model/submit_cases_from_downloads.py b/examples/Solver_Features/Wall_Model/submit_cases_from_downloads.py new file mode 100644 index 0000000..2bd0c86 --- /dev/null +++ b/examples/Solver_Features/Wall_Model/submit_cases_from_downloads.py @@ -0,0 +1,64 @@ +"""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/caseStudies/wallModel/Meshes/Windsor_Wall_Resolved_1e-06.b8.ugrid" +MESH_FILENAME = "Windsor_Wall_Resolved_1e-06.b8.ugrid" + +if not os.path.isfile(MESH_FILENAME): + urlretrieve(URL, MESH_FILENAME) + +URL2 = "https://simcloud-public-1.s3.amazonaws.com/caseStudies/wallModel/Meshes/Windsor_Wall_Model_5e-04.b8.ugrid" +MESH_FILENAME2 = "Windsor_Wall_Model_5e-04.b8.ugrid" + +if not os.path.isfile(MESH_FILENAME2): + urlretrieve(URL2, MESH_FILENAME2) + + +# upload the wall resolved mesh +volume_mesh = fl.VolumeMesh.from_file(MESH_FILENAME, name="Windsor_Wall_Resolved_Mesh") +volume_mesh = volume_mesh.submit() + + +# upload the wall model mesh +volume_mesh2 = fl.VolumeMesh.from_file(MESH_FILENAME2, name="Windsor_Wall_Modeled_Mesh") +volume_mesh2 = volume_mesh2.submit() + +# submit wall-resolved case using json file +params = fl.Flow360Params("Flow360.json") +case = fl.Case.create("Windsor_Wall_Resolved", params, volume_mesh.id) +case_name_list.append(case.name) +case = case.submit() + +# change noSlipWall to wallFunction in params + +Boundaries = params.boundaries +params.boundaries = Boundaries.copy( + update={ + "1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), + "4": fl.WallFunction(name="Flow.CFDWT.Floor"), + "8": fl.WallFunction(name="Windsor"), + "9": fl.WallFunction(name="Windsor_rear"), + "10": fl.WallFunction(name="Windsor_supports"), + } +) + +# submit wall-modeled case using updated parameters + +case2 = fl.Case.create("Windsor_Wall_Modeled", params, volume_mesh2.id) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case names 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/Solver_Features/Wall_Model/submit_cases_from_id.py b/examples/Solver_Features/Wall_Model/submit_cases_from_id.py new file mode 100644 index 0000000..548a1a5 --- /dev/null +++ b/examples/Solver_Features/Wall_Model/submit_cases_from_id.py @@ -0,0 +1,37 @@ +"""Case submission from mesh ID's present on the Flexcompute servers""" + +import flow360 as fl + +case_name_list = [] + +MESH_ID_WALL_RESOLVED = "2f71bda6-b218-4fb2-9a2b-d79a4d3c5384" +MESH_ID_WALL_MODEL = "4ff4782e-9ad1-4bed-ab2d-419a07cc512b" + + +# submit wall-resolved case using json file +params = fl.Flow360Params("Flow360.json") +case = fl.Case.create("Windsor_Wall_Resolved", params, MESH_ID_WALL_RESOLVED) +case_name_list.append(case.name) +case = case.submit() + +# change noSlipWall to wallFunction in params +Boundaries = params.boundaries +params.boundaries = Boundaries.copy( + update={ + "1": fl.WallFunction(name="Flow.CFDWT.FloorUnder"), + "4": fl.WallFunction(name="Flow.CFDWT.Floor"), + "8": fl.WallFunction(name="Windsor"), + "9": fl.WallFunction(name="Windsor_rear"), + "10": fl.WallFunction(name="Windsor_supports"), + } +) + +# submit wall-modeled case using updated parameters +case2 = fl.Case.create("Windsor_Wall_Modeled", params, MESH_ID_WALL_MODEL) +case_name_list.append(case2.name) +case2 = case2.submit() + +# dump case names 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") From 63161d95ea219963f9ae939094e0e1c5614ed8dd Mon Sep 17 00:00:00 2001 From: Thomas Fitzgibbon Date: Tue, 9 Jan 2024 15:38:55 +0000 Subject: [PATCH 14/14] Removed old JSON file --- .../Adaptive_CFL/XV15/Flow360.json | 40 +++------ .../Adaptive_CFL/XV15/Flow360_New.json | 86 ------------------- 2 files changed, 10 insertions(+), 116 deletions(-) delete mode 100644 examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json index 09752ab..16e2eb1 100644 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json +++ b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360.json @@ -52,12 +52,6 @@ "stationaryField/farfield": { "type": "Freestream" }, - "stationaryField/rotationInterface_static": { - "type": "SlidingInterface" - }, - "rotationField/rotBnd": { - "type": "SlidingInterface" - }, "rotationField/blade": { "type": "NoSlipWall" }, @@ -68,30 +62,16 @@ "type": "NoSlipWall" } }, - "slidingInterfaces": [ - { - "stationaryPatches": [ - "stationaryField/rotationInterface_static" - ], - "rotatingPatches": [ - "rotationField/rotBnd" - ], - "axisOfRotation": [ - 0, - 0, - -1 - ], - "centerOfRotation": [ - 0, - 0, - 0 - ], - "omega": 0.0036, - "volumeName": [ - "rotationField" - ] - } - ], + "volumeZones":{ + "rotationField":{ + "modelType": "FluidDynamics", + "referenceFrame":{ + "axisOfRotation" : [0,0,-1], + "centerOfRotation" : [0,0,0], + "omega" : 0.0036 + } + } + }, "timeStepping": { "timeStepSize": 29.08882086657216, "physicalSteps": 120, diff --git a/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json b/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json deleted file mode 100644 index 16e2eb1..0000000 --- a/examples/Solver_Features/Adaptive_CFL/XV15/Flow360_New.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "geometry": { - "refArea": 70685.83470577035, - "momentCenter": [ - 0, - 0, - 0 - ], - "momentLength": [ - 150, - 150, - 150 - ] - }, - "volumeOutput": { - "outputFormat": "paraview", - "outputFields" : ["primitiveVars", "qcriterion", "Mach"] - }, - "surfaceOutput": { - "outputFormat": "paraview", - "outputFields" : ["primitiveVars", "Cp", "Cf", "CfVec", "yPlus"] - }, - "navierStokesSolver": { - "absoluteTolerance": 1e-9, - "relativeTolerance": 0.01, - "linearIterations": 35, - "kappaMUSCL": -1, - "orderOfAccuracy": 1, - "updateJacobianFrequency": 1, - "equationEvalFrequency": 1 - }, - "turbulenceModelSolver": { - "modelType": "SpalartAllmaras", - "absoluteTolerance": 1e-8, - "relativeTolerance": 0.01, - "linearIterations": 35, - "DDES": true, - "orderOfAccuracy": 1, - "updateJacobianFrequency": 1, - "equationEvalFrequency": 1, - "rotationCorrection": true - }, - "freestream": { - "muRef": 0.00000168, - "Mach": 0.182, - "MachRef": 0.54, - "Temperature": 288.15, - "alphaAngle": -90, - "betaAngle": 0 - }, - "boundaries": { - "stationaryField/farfield": { - "type": "Freestream" - }, - "rotationField/blade": { - "type": "NoSlipWall" - }, - "rotationField/blade_2": { - "type": "NoSlipWall" - }, - "rotationField/blade_3": { - "type": "NoSlipWall" - } - }, - "volumeZones":{ - "rotationField":{ - "modelType": "FluidDynamics", - "referenceFrame":{ - "axisOfRotation" : [0,0,-1], - "centerOfRotation" : [0,0,0], - "omega" : 0.0036 - } - } - }, - "timeStepping": { - "timeStepSize": 29.08882086657216, - "physicalSteps": 120, - "maxPseudoSteps": 13, - "CFL": { - "type": "ramp", - "initial": 1, - "final": 1000, - "rampSteps": 11 - } - } -}