From 896106a25675fbd026a7f450f2d01b91fe7e8bf4 Mon Sep 17 00:00:00 2001 From: JustinBonus Date: Mon, 13 May 2024 17:43:49 -0700 Subject: [PATCH 1/5] Clean examples config so they appear in examples drop down --- Examples/Examples.json | 4 +- Examples/hdro-0001/README.rst | 41 +++--- Examples/hdro-0002/meta.yaml | 2 +- Examples/hdro-0003/README.rst | 119 +++++++++++----- Examples/hdro-0003/meta.yaml | 2 +- Examples/hdro-0004/README.rst | 249 ++++++++++++++++++---------------- Examples/hdro-0004/meta.yaml | 2 +- Examples/index.json | 28 +++- 8 files changed, 272 insertions(+), 175 deletions(-) diff --git a/Examples/Examples.json b/Examples/Examples.json index bb578ce6..5ecc79aa 100644 --- a/Examples/Examples.json +++ b/Examples/Examples.json @@ -1,7 +1,7 @@ { "Examples": [ { - "name": "E1: Simple Example", + "name": "E1: Simple Multi-Story Structure Example", "description": "This example takes a brief look at uncertainty quantification in a three story shear frame subjected to earthquake loading.", "inputFile": "hdro-0001/src/input.json" }, @@ -11,7 +11,7 @@ "inputFile": "hdro-0002/src/input.json" }, { - "name": "E3: Coupled Digital Twin - Simple Cantilevered Cylinder Half-Submerged in Crossflow", + "name": "E3: Digital Twin of UW WASIRF - Coupled Digital Twin - Simple Cantilevered Cylinder Half-Submerged in Crossflow", "description": "This example takes a brief look at uncertainty quantification in a three story shear frame subjected to earthquake loading.", "inputFile": "hdro-0003/src/input.json" }, diff --git a/Examples/hdro-0001/README.rst b/Examples/hdro-0001/README.rst index bd1432eb..aaa78f97 100644 --- a/Examples/hdro-0001/README.rst +++ b/Examples/hdro-0001/README.rst @@ -41,30 +41,27 @@ The dataset in this example originates from experimental tests conducted in the Coupled Digital Twin Illustration + Model ^^^^^ This model is characterized by the parameters: * Structural weight, :math:`w`, in kN as a random variable with a mean of 100 kN and a standard deviation of 10 kN. - - -Files required -^^^^^^^^^^^^^^ - - - +^ .. warning:: **Do NOT** place the files in your ``root``, ``downloads``, or ``desktop`` folder. The running application will copy every unrelated file in the directories and subdirectories multiple times. -UQ workflow + +Workflow ^^^^^^^^^^^ The inputs needed to run this example can be loaded into the HydroUQ user interface by selecting the ``Coupled Digital Twin`` example from the ``Examples`` menu at the top of the application. The inputs can also be set up manually through the following steps: -#. Start the application and the **UQ** panel will be highlighted. In the **UQ Method** drop-down menu, select the **Bayesian Calibration** option. In the **UQ Engine** dropdown menu select **UCSD-UQ** option. In the **Model** dropdown, select the **Hierarchical** option. Enter the values in this panel as shown in the figure below. A brief explanation of the different user input fields can be found in the :ref:`User Manual `. +#. Start the application and select the **UQ** panel: + In the **UQ Method** drop-down menu, select the **Bayesian Calibration** option. In the **UQ Engine** dropdown menu select **UCSD-UQ** option. In the **Model** dropdown, select the **Hierarchical** option. Enter the values in this panel as shown in the figure below. A brief explanation of the different user input fields can be found in the :ref:`User Manual `. .. _figHBMUQ: @@ -75,7 +72,8 @@ The inputs can also be set up manually through the following steps: Inputs in the UQ panel -#. Next in the **FEM** panel , select **OpenSees** and populate the **Input Script** field by choosing the path to the model file. +#. Next in the **FEM** panel: + Select **OpenSees** and populate the **Input Script** field by choosing the path to the model file. .. _figHBMFEM: @@ -86,7 +84,8 @@ The inputs can also be set up manually through the following steps: Inputs in the FEM panel -#. Select the **RV** tab from the input panel. This panel should be pre-populated with the names of the variables that were defined in the model scripts. If not, press the **Add** button to create a new field to define the input random variable. Enter the same variable name, as required in the model script. For this example, choose the Normal probability distribution for all the random variables and enter the parameter values for each distribution as shown in the figures below: +#. Select the **RV** tab from the input panel: + This panel should be pre-populated with the names of the variables that were defined in the model scripts. If not, press the **Add** button to create a new field to define the input random variable. Enter the same variable name, as required in the model script. For this example, choose the Normal probability distribution for all the random variables and enter the parameter values for each distribution as shown in the figures below: .. _figHBMRV: @@ -112,7 +111,8 @@ The inputs can also be set up manually through the following steps: .. Inputs in the RV panel -#. In the **EDP** panel create the output quantities corresponding to each of the experiments with a descriptive name, as shown in the figures below: +#. In the **EDP** panel: + Create the output quantities corresponding to each of the experiments with a descriptive name, as shown in the figures below: .. .. _figHBMEDP1: @@ -131,9 +131,14 @@ The inputs can also be set up manually through the following steps: .. Inputs in the EDP panel -#. Click on the **Run** button. This will create the necessary input files to perform a Bayesian calibration of the hierarchical model, run the analysis, and display the results when the analysis is completed. The results produced are sample values drawn from the distribution that represents the aleatory uncertainty in the estimated material parameters from each of the datasets. +#. Click on the **Run** button. + This will create the necessary input files to perform a Bayesian calibration of the hierarchical model, run the analysis, and display the results when the analysis is completed. + +#. The **RES** tab will open with the workflow results when the simulation completers. The results produced are sample values drawn from the distribution that represents the aleatory uncertainty in the estimated material parameters from each of the datasets. -The **Summary** tab shows the mean, standard deviation, and coefficient of variation of each of the seven parameters of the material model that were inferred in this example. + The **Summary** tab shows the mean, standard deviation, and coefficient of variation of each of the seven parameters of the material model that were inferred in this example. + + In the **Data Values** tab of the **RES** panel, a chart and a table with all the sample values are shown. By clicking on the data inside the columns of the chart with the **left** or **right** mouse button (``M1`` and ``M2``), different chart types are created and shown in the chart area on the left. .. .. _figHBMRES1: @@ -152,7 +157,6 @@ The **Summary** tab shows the mean, standard deviation, and coefficient of varia .. Results in the **RES** panel summary tab -In the **Data Values** tab of the **RES** panel, a chart and a table with all the sample values are shown. By clicking on the data inside the columns of the chart with the left or right mouse button, different chart types are created and shown in the chart area on the left. .. .. _figHBMRES3: @@ -173,10 +177,9 @@ In the **Data Values** tab of the **RES** panel, a chart and a table with all th .. _lblHBMRestart: -Files for restarting the analysis ---------------------------------- - -In addition to the results displayed in the **RES** panel in ``HydroUQ``, JSON files with the state of the chain at every step of the sampling algorithm are saved in a directory called ``sampling_results`` within the ``tmp.SimCenter`` directory inside the jobs directory specified in the ``HydroUQ`` Preferences menu. Any of these files can be used to resume the sampling, by copying the file to the directory containing the model files and specifying its name in the Restart File Name field in the **UQ** panel. +.. info:: + In addition to the results displayed in the **RES** panel in ``HydroUQ``, JSON files with the state of the chain at every step of the sampling algorithm are saved in a directory called ``sampling_results`` within the ``tmp.SimCenter`` directory inside the jobs directory specified in the ``HydroUQ`` Preferences menu. + Any of these files can be used to resume the sampling, by copying the file to the directory containing the model files and specifying its name in the Restart File Name field in the **UQ** panel. .. warning:: The ``tmp.SimCenter`` directory is cleared every time the ``RUN`` button is clicked in ``HydroUQ``. So, if you want to restart the analysis using one of the sampling results files outlined above, make sure to copy the results file to a location outside the ``tmp.SimCenter`` directory at the end of the analysis. diff --git a/Examples/hdro-0002/meta.yaml b/Examples/hdro-0002/meta.yaml index 27c3a822..f66ffb99 100644 --- a/Examples/hdro-0002/meta.yaml +++ b/Examples/hdro-0002/meta.yaml @@ -1,2 +1,2 @@ summary: This example uses the Material Point Method (MPM) running on GPUs to simulate the OSU LWF in 3D with debris. -difficulty: 1 \ No newline at end of file +difficulty: 1 diff --git a/Examples/hdro-0003/README.rst b/Examples/hdro-0003/README.rst index 66dd4a15..b9b334e3 100644 --- a/Examples/hdro-0003/README.rst +++ b/Examples/hdro-0003/README.rst @@ -1,7 +1,7 @@ .. _hdro-0003: ======================================================================================= -Coupled Digital Twin Example - Simple Cantilevered Cylinder Half-Submerged in Crossflow +Cylinder Half-Submerged in Flow - UW WASIRF Twin - FOAMySees (OpenFOAM + OpenSees) ======================================================================================= +---------------+------------------------------------------------------------------------------------------------------+ @@ -47,28 +47,30 @@ The **EDP** tab will then process these results. Set-Up ------ -The case is set up in the HydroUQ tool on DesignSafe. You can select the case from the list of available examples off of the HydroUQ menubar, i.e. ``Examples / hdro-0003``. - -The case is set up with the following parameters: +The case is set up in the HydroUQ tool on DesignSafe. You can select the case from the list of available examples off of the HydroUQ menubar, i.e. ``Examples / hdro-0003``. The case is set up as follows. The flume is 1 meter wide (from Y=-0.5m to Y=0.5 m), 1 meter tall (Z=0.0m to Z=1.0m), and 4 meters long (X=0.0m to X=4.0m). The cardinal direction Z+ is vertical, X+ is downstream, and Y+ is crossflow. Gravity is -9.81 m / s^2 in the Z direction. -The case is initialized with a still water level of 0.25 meters. The velocity at the inlet is given a time history boundary condition (src/VelTime.csv). +The case is initialized with a still water level of 0.25 meters. The velocity at the inlet is given a time history boundary condition, ``src/VelTime.csv``. -This structure is a simple cylinder, with diameter 0.1 meters, located at X=1.5, Y=0.0, Z=0.0. The interface surface file is 'src/interface.stl'. +This structure is a simple cylinder. It has a diameter 0.1 meters and it is located at X=1.5, Y=0.0, Z=0.0. The length of the cylinder is 0.5 meters in Z+. The cylinder is represented in OpenSees by a cantilevered beam, with an elastic section, modelled with displacement-action controlled beam elements. The bottom of the cantilevered beam is fixed at Z=0.0. -The constrained node is removed from the coupled solution, by omitting it from the list 'coupledNodes' in the OpenSees model file. +The constrained node is removed from the coupled solution, by omitting it from the list *coupledNodes* in the OpenSees model file. + +The interface surface file is ``'src/interface.stl'``. + -The length of the cylinder is 0.5 meters. +.. _hdro-0003-fig-schematic: .. figure:: figures/hdro-0003 example.png :align: center :width: 600 :figclass: align-center - + + Schematic of the digital twin example in the UW WASIRF truncated flume Probe positions in the digital flume are set at the following locations: @@ -76,7 +78,8 @@ Probe positions in the digital flume are set at the following locations: :align: center :width: 600 :figclass: align-center - + + Instrumentation locations in theUW WASIRF truncated digital flume Inlet Velocity Time History (U(t)) for the truncated digital twin is given by the following function in OpenFOAM: @@ -84,9 +87,11 @@ Inlet Velocity Time History (U(t)) for the truncated digital twin is given by th :align: center :width: 600 :figclass: align-center + + Inlet Velocity Time History for the UW WASIRF digital twin -We now have a coupled simulation configured for fluid flow around, and the structural response of, a cylinder. +We now have a coupled simulation configured for fluid flow around, and the structural response of, a cylinder. Next, we will run the simulation on a remote TACC high-performance computing system. .. _hdro-0003-simulation: @@ -96,26 +101,30 @@ Simulation Login to DesignSafe and submit the job to run remotely on a TACC system, either *Frontera* or *Stampede3*. - Simulation time for 1 second in the digital flume took 1 hour and 20 minutes. This was using one computational node on TACC Frontera, possessing 56 cores. The case can be run for as long as desired, but mind that the longer the case runs, the longer the postprocessing routines will be. In order to retrieve results from the analysis, the job must complete and postprocess the model output files into a VTK format before the end of the allotted submission time. -Provide a large amount of time for the 'Max Run Time' field in HydroUQ when submitting a job to ensure the model completes before the time allotted runs out! +.. important:: + Provide a large amount of time for the *Max Run Time* field in HydroUQ when submitting a job to ensure the model completes before the time allotted runs out! -Be aware that the smaller the OpenFOAM Outputs and OpenSees Outputs 'Time Interval' value is, the longer the post processing of the case will take after analysis has completed, and the larger the results.zip folder will be. +.. note:: + Be aware that the smaller the OpenFOAM Outputs and OpenSees Outputs *Time Interval* value is, the longer the post processing of the case will take after analysis has completed, + and the larger the ``results.zip`` folder will be. .. warning:: Be modest when requesting simulation outputs across many recording probes or full geometry snapshots. Only ask for what you need, or your simulation will become slow due to I/O constraints and the output data will be too large to effecitvely post-process or host on your local machine. -.. _hdro-0003-postprocessing: -Post-Processing ---------------- + +.. _hdro-0003-results: + +Get Results +----------- First, we must retrieve the ``results.zip`` folder from the DesignSafe file storage. This zip file will contain all our from the Tools and Applications Page of Design Safe @@ -180,6 +189,13 @@ The results folder should look something like this. This is the output of the model + + +.. _hdro-0003-analysis: + +Analysis +-------- + Paraview files have a .PVD extension. Open VTK/Fluid.vtm.series to look at OpenFOAM results. Open OpenSeesOutput.pvd to look at OpenSees results. @@ -208,9 +224,7 @@ OpenSees Displacements And Reactions This is the model output data as seen from ParaView -OpenFOAM probe and function object output is available in results/postProcessing/. - -OpenFOAM output is messy. An example Matlab script is provided in the /src/ directory to post process the OpenFOAM output for this particular case and output. +OpenFOAM probe and function object output is available in ``results/postProcessing/``. OpenFOAM output is currently unorganized. An example Matlab script is provided in the ``src/`` directory to post process the OpenFOAM output for this particular case and output. This file can be modified to work for any case. The names of the data folders will need to be changed according to the name of the probe given in HydroUQ. .. figure:: figures/MatlabScriptCopyToLocation.PNG @@ -220,54 +234,95 @@ This file can be modified to work for any case. The names of the data folders wi In the /src/ folder in the hrdo-0003 folder, an example matlab script is provided to look at time history data of the output probes -OpenFOAM Calculated Story Forces +OpenFOAM Calculated Story Forces are .. figure:: figures/storyForces.png :align: center :width: 600 :figclass: align-center - Story Forces + + Story Forces in OpenFOAM -OpenFOAM Calculated Coupled Interface Forces +OpenFOAM Calculated Coupled Interface Forces are visualized in the following figure .. figure:: figures/Forces.png :align: center :width: 600 :figclass: align-center - Forces + + Coupled Interface Forces in OpenFOAM-OpenSees -OpenFOAM Calculated Coupled Interface Moments +OpenFOAM calculated, coupled interface moments at the structural surface are .. figure:: figures/Moments.png :align: center :width: 600 :figclass: align-center - Moments + + Coupled Interface Moments in OpenFOAM-OpenSees -OpenFOAM Calculated Pressure Probe Values +OpenFOAM calculated pressure probe values throughout the flume are .. figure:: figures/Pressures.png :align: center :width: 600 :figclass: align-center - Pressures + Pressure Probe Values in OpenFOAM -OpenFOAM Calculated Velocity Probe Values +OpenFOAM calculated fluid velocity probe values throughout the flume are .. figure:: figures/Velocities.png :align: center :width: 600 :figclass: align-center - Velocities + + Velocity Probe Values in OpenFOAM -OpenFOAM Calculated Free Surface Values +OpenFOAM calculated wave gauge free-surface values at key locations in the facility are .. figure:: figures/WaveGauges.png :align: center :width: 600 :figclass: align-center - Wave Gauges + + Wave Gauge Free-Surface Probe Values in OpenFOAM + +This completes the analysis of the model. In validation of any flume experimental case, a similar process may be employed with an added step of comparison to experimental data. + + + +.. _hdro-0003-references: + +References +---------- + +.. [Lewis2023] + Lewis, N. (2023). Development of An Open-Source Methodology for Simulation of Civil Engineering Structures Subject to Multi-Hazards. *PhD thesis*, University of Washington, Seattle, WA. ISBN: 979-8-381408-69-0. + +.. [OpenFOAM] + OpenFOAM. OpenFOAM Foundation. https://www.openfoam.com/ + +.. [OpenSees] + OpenSees. Pacific Earthquake Engineering Research Center. http://opensees.berkeley.edu/ + +.. [Paraview] + Paraview. Kitware. https://www.paraview.org/ + +.. [DesignSafe] + DesignSafe**. DesignSafe-CI. https://www.designsafe-ci.org/ + +.. [TACC] + TACC. Texas Advanced Computing Center. https://www.tacc.utexas.edu/ + +.. [Frontera] + Frontera. Texas Advanced Computing Center. https://frontera-portal.tacc.utexas.edu/ + +.. [Stampede3] + Stampede3. Texas Advanced Computing Center. https://stampede2.tacc.utexas.edu/ + + + diff --git a/Examples/hdro-0003/meta.yaml b/Examples/hdro-0003/meta.yaml index 78c06fb0..9555d7ea 100644 --- a/Examples/hdro-0003/meta.yaml +++ b/Examples/hdro-0003/meta.yaml @@ -1,2 +1,2 @@ summary: This example uses a coupled CFD - FEM simulation -difficulty: 0 \ No newline at end of file +difficulty: 1 diff --git a/Examples/hdro-0004/README.rst b/Examples/hdro-0004/README.rst index 0d93493d..a2a5c976 100644 --- a/Examples/hdro-0004/README.rst +++ b/Examples/hdro-0004/README.rst @@ -1,43 +1,39 @@ .. _hdro-0004: +=============================================================================== Tsunami Debris Motion Through a Scaled Port Setting - WU TWB Digital Twin - MPM -============================ +=============================================================================== +---------------+----------------------------------------------+ | Problem files | :github:`Github ` | +---------------+----------------------------------------------+ -Outline -------- -Example to demonstrate how to run a MPM simulation to determine floor loads on a building and then perform -an OpenSees simulation of the building assuming uncertainties in the building properties. - -The flume is 1 meter wide (from Y=-0.5m to Y=0.5 m), 1 meter tall (Z=0.0m to Z=1.0m), and 4 meters long (X=0.0m to X=4.0m). +.. contents:: Table of Contents + :local: + :backlinks: none -The case is initialized with a still water level of 0.25 meters. The velocity at the inlet is given a time history boundary condition (src/VelTime.csv). +.. _hdro-0004-overview: -This structure is a simple cylinder, with diameter 0.1 meters, located at X=1.5, Y=0.0, Z=0.0. The interface surface file is 'src/interface.stl'. - -The cylinder is represented in OpenSees by a cantilevered beam, with an elastic section, modelled with displacement-action controlled beam elements. The bottom of the cantilevered beam is fixed at Z=0.0. +Outline +------- -The constrained node is removed from the coupled solution, by omitting it from the list 'coupledNodes' in the OpenSees model file. +Example to demonstrate how to run a MPM simulation to determine loads on an array of port buildings during a tsunami with respect to debris impacts and damming. After, we perform +an OpenSees simulation of one building assuming uncertainties in the building properties. -The length of the cylinder is 0.5 meters. +The Waseda University Tsunami Wave Basin (WU TBW) flume is 4 meter wide (from X=-2m to X=2 m), 1 meter tall (Z=0.0m to Z=1.0m), and 9 meters long (Y=0.0m to Y=9.0m). -The flow around the cylinder is calculated for a given period of time. +The case is initialized with a still water level of 0.23 meters. -Outputs: -Results for free surface, velocity, and pressure, as well as interface forces and moments and a cut section of the case at a specified interval. +Results for free surface, velocity, and pressure, as well as structural load forces are output at a specified interval to match experimental instruments. -Simulation of MPM debris impacts on one row of five obstacles .. figure:: figures/TOKYO_BoreFrontImage_Debris3_o5x1_Frame20_29072023.png :align: center :width: 600 :figclass: align-center - -Schematic of the flume and sensor locations + + Simulation of MPM debris impacts on one row of five obstacles .. figure:: figures/B4_Flume_Schematic.png @@ -45,24 +41,23 @@ Schematic of the flume and sensor locations :width: 600 :figclass: align-center + Schematic of the flume and sensor locations -Smart debris used in experiments .. figure:: figures/B4_Debris_Picture.PNG :align: center :width: 600 :figclass: align-center + Smart debris used in experiments -CASE RUN TIME ---------------- -Simulation Time: 6 seconds - Ran on TACC Lonestar6, 56 processors, 3 NVIDIA A100 GPUs, 1 node -> Real Time: 1hr, 20 minutes +.. _hdro-0004-simulation: + +Simulation +---------- -Submitted -Oct 8, 2023 1:14:37 PM -Finished -Oct 8, 2023 2:34:10 PM +Simulation Time: 6 seconds - Ran on TACC Lonestar6, 56 processors, 3 NVIDIA A100 GPUs, 1 node -> Real Time: 1hr, 20 minutes The case can be run for as long as desired, but mind that the longer the case runs, the longer the postprocessing routines will be. @@ -72,11 +67,15 @@ Provide a large amount of time for the 'Max Run Time' field in HydroUQ when subm Be aware that the smaller the OpenFOAM Outputs and OpenSees Outputs 'Time Interval' value is, the longer the post processing of the case will take after analysis has completed, and the larger the results.zip folder will be. -USE CAUTION WHEN REQUESTING OUTPUT! Only ask for what you need, or you will end up will massive amounts of data. +.. warning:: + Use caution when requesting sensors and using high sampling rates. Only ask for what you need, or you will end up will massive amounts of data. + -Post Processing -------------------------------------------------------------------- +.. _hdro-0004-analysis: + +Analysis +-------- Retrieving the results.zip folder from the Tools and Applications Page of Design Safe.. @@ -84,7 +83,8 @@ Retrieving the results.zip folder from the Tools and Applications Page of Design :align: center :width: 600 :figclass: align-center - Locating the job files on DesignSafe + + Locating the job files on DesignSafe Check if the job has finished. If it has, click 'More info'. @@ -92,7 +92,8 @@ Check if the job has finished. If it has, click 'More info'. :align: center :width: 600 :figclass: align-center - Once the job is finished, the output files should be available in the directory which the analysis results were sent to + + Once the job is finished, the output files should be available in the directory which the analysis results were sent to Find the files by clicking 'View'. @@ -100,7 +101,8 @@ Find the files by clicking 'View'. :align: center :width: 600 :figclass: align-center - Locating this directory is easy. + + Locating this directory is easy. Move the results.zip to somewhere in My Data/. Use the Extractor tool available on DesignSafe. Unzip the results.zip folder. @@ -117,7 +119,8 @@ OR Download the results.zip folder to your PC and unzip to look at the model res :align: center :width: 600 :figclass: align-center - Download the results to look at the VTK files of the analysis. This will include OpenFOAM and OpenSees field data and model geometry + + Download the results to look at the VTK files of the analysis. This will include OpenFOAM and OpenSees field data and model geometry Extract the Zip folder either on DesignSafe or on your local machine. You will need Paraview to view the model data. @@ -125,101 +128,117 @@ Extract the Zip folder either on DesignSafe or on your local machine. You will n :align: center :width: 600 :figclass: align-center - Locate the zip folder and extract it to somewhere convenient - -The results folder should look something like this. - -.. figure:: figures/results.png - :align: center - :width: 600 - :figclass: align-center - This is the output of the model - -Paraview files have a .PVD extension. Open VTK/Fluid.vtm.series to look at OpenFOAM results. -Open OpenSeesOutput.pvd to look at OpenSees results. - -.. figure:: figures/Paraview.PNG - :align: center - :width: 600 - :figclass: align-center - This is the model output data as seen from ParaView - -OpenSees Displacements And Reactions - - -.. figure:: figures/TipDisplacement.png - :align: center - :width: 600 - :figclass: align-center - This is the model output data as seen from ParaView - -.. figure:: figures/ReactionForces.png - :align: center - :width: 600 - :figclass: align-center - This is the model output data as seen from ParaView + + Locate the zip folder and extract it to somewhere convenient -OpenFOAM probe and function object output is available in results/postProcessing/. - -OpenFOAM output is messy. An example Matlab script is provided in the /src/ directory to post process the OpenFOAM output for this particular case and output. -This file can be modified to work for any case. The names of the data folders will need to be changed according to the name of the probe given in HydroUQ. - -.. figure:: figures/MatlabScriptCopyToLocation.PNG - :align: center - :width: 600 - :figclass: align-center - In the /src/ folder in the hdro-0004 folder, an example matlab script is provided to look at time history data of the output probes +.. The results folder should look something like this. +.. .. figure:: figures/results.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. This is the output of the model -OpenFOAM Calculated Story Forces - -.. figure:: figures/storyForces.png - :align: center - :width: 600 - :figclass: align-center - Story Forces +.. Paraview files have a .PVD extension. Open VTK/Fluid.vtm.series to look at OpenFOAM results. +.. Open OpenSeesOutput.pvd to look at OpenSees results. + +.. .. figure:: figures/Paraview.PNG +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. This is the model output data as seen from ParaView + +.. OpenSees Displacements And Reactions + +.. .. figure:: figures/TipDisplacement.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. This is the model output data as seen from ParaView + +.. .. figure:: figures/ReactionForces.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. This is the model output data as seen from ParaView + + +.. OpenFOAM probe and function object output is available in results/postProcessing/. + +.. OpenFOAM output is messy. An example Matlab script is provided in the /src/ directory to post process the OpenFOAM output for this particular case and output. +.. This file can be modified to work for any case. The names of the data folders will need to be changed according to the name of the probe given in HydroUQ. + +.. .. figure:: figures/MatlabScriptCopyToLocation.PNG +.. :align: center +.. :width: 600 +.. :figclass: align-center +.. In the /src/ folder in the hdro-0004 folder, an example matlab script is provided to look at time history data of the output probes -OpenFOAM Calculated Coupled Interface Forces - -.. figure:: figures/Forces.png - :align: center - :width: 600 - :figclass: align-center - Forces + +.. OpenFOAM Calculated Story Forces + +.. .. figure:: figures/storyForces.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. Story Forces + +.. OpenFOAM Calculated Coupled Interface Forces + +.. .. figure:: figures/Forces.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. Forces -OpenFOAM Calculated Coupled Interface Moments +.. OpenFOAM Calculated Coupled Interface Moments -.. figure:: figures/Moments.png - :align: center - :width: 600 - :figclass: align-center - Moments +.. .. figure:: figures/Moments.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. Moments -OpenFOAM Calculated Pressure Probe Values +.. OpenFOAM Calculated Pressure Probe Values -.. figure:: figures/Pressures.png - :align: center - :width: 600 - :figclass: align-center - Pressures +.. .. figure:: figures/Pressures.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. Pressures -OpenFOAM Calculated Velocity Probe Values +.. OpenFOAM Calculated Velocity Probe Values -.. figure:: figures/Velocities.png - :align: center - :width: 600 - :figclass: align-center - Velocities +.. .. figure:: figures/Velocities.png +.. :align: center +.. :width: 600 +.. :figclass: align-center +.. Velocities -OpenFOAM Calculated Free Surface Values +.. OpenFOAM Calculated Free Surface Values -.. figure:: figures/WaveGauges.png - :align: center - :width: 600 - :figclass: align-center - Wave Gauges +.. .. figure:: figures/WaveGauges.png +.. :align: center +.. :width: 600 +.. :figclass: align-center + +.. Wave Gauges + + +.. _hdro-0004-references: + +References +---------- diff --git a/Examples/hdro-0004/meta.yaml b/Examples/hdro-0004/meta.yaml index 35d9c288..a5b2c898 100644 --- a/Examples/hdro-0004/meta.yaml +++ b/Examples/hdro-0004/meta.yaml @@ -1,2 +1,2 @@ summary: This example uses the Material Point Method (MPM) running on GPUs to simulate the WU TWB in 3D with debris. -difficulty: 1 \ No newline at end of file +difficulty: 2 diff --git a/Examples/index.json b/Examples/index.json index 27c2e168..6453c524 100644 --- a/Examples/index.json +++ b/Examples/index.json @@ -2,7 +2,7 @@ "items": { "hdro-0001": { "id": "hdro-0001", - "title": "Wave flume Coupled Digital twin", + "title": "Multi-Story Structure - OSU LWF Digital Twin - OpenFOAM", "base": "hdro-0001", "doc": [ "hdro-0001/figures/openfoam.png", @@ -22,7 +22,7 @@ }, "hdro-0002": { "id": "hdro-0002", - "title": "Debris Impacts on a Rigid Structure - OSU Large Wave Flume Digital Twin - MPM", + "title": "Debris Impacts on a Structure - OSU LWF Digital Twin - MPM", "base": "hdro-0002", "doc": [ "hdro-0002/figures/HydroUQ_MPM_3DViewPort_OSULWF_2024.04.25.gif", @@ -68,11 +68,31 @@ }, "hdro-0003": { "id": "hdro-0003", - "title": "Half-Submerged Cylinder in Flow - Digital Twin - Coupled CFD-FEM", + "title": "Cylinder in Flow - UW WASIRF Digital Twin - OpenFOAM + OpenSees", "base": "hdro-0003", "doc": [ "hdro-0003/figures/openfoam.png", "hdro-0003/figures/opensees.png", + "hdro-0003/figures/downloadResults.PNG", + "hdro-0003/figures/DSToolsAndAppsJobsStatus.PNG", + "hdro-0003/figures/DSToolsAndAppsJobsStatusFinished.PNG", + "hdro-0003/figures/DSToolsANdAppsJobsStatusViewFiles.PNG", + "hdro-0003/figures/extractonDS.PNG", + "hdro-0003/figures/resultsZip.png", + "hdro-0003/figures/Forces.png", + "hdro-0003/figures/hdro-0003example.png", + "hdro-0003/figures/hdro-0003exampleprobeLoc.png", + "hdro-0003/figures/inletVTH.png", + "hdro-0003/figures/MatlabScriptCopyToLocation.PNG", + "hdro-0003/figures/Moments.png", + "hdro-0003/figures/Paraview.PNG", + "hdro-0003/figures/Pressures.png", + "hdro-0003/figures/ReactionForces.png", + "hdro-0003/figures/results.png", + "hdro-0003/figures/storyForces.png", + "hdro-0003/figures/TipDisplacement.png", + "hdro-0003/figures/Velocities.png", + "hdro-0003/figures/WaveGauges.png", "hdro-0003/README.rst" ], "entry_point": "hdro-0003/./input.json", @@ -84,7 +104,7 @@ }, "hdro-0004": { "id": "hdro-0004", - "title": "Tsunami Debris Motion Through a Scaled Port Setting - WU TWB Digital Twin - MPM", + "title": "Tsunami Debris Motion In a Scaled Port Setting - WU TWB Digital Twin - MPM", "base": "hdro-0004", "doc": [ "hdro-0004/figures/TOKYO_BoreFrontImage_Debris3_o5x1_Frame20_29072023.png", From 5535ef67812eced534c357588798b7eb22bf1aff Mon Sep 17 00:00:00 2001 From: JustinBonus Date: Tue, 14 May 2024 05:06:52 -0700 Subject: [PATCH 2/5] formatting SimpleWaves class structure and deps for welib python package --- EVENTS/SimpleWaves/SimpleWaves.cpp | 549 +++++++++++++++++++++++++++++ EVENTS/SimpleWaves/SimpleWaves.h | 149 ++++++++ requirements.txt | 8 + 3 files changed, 706 insertions(+) create mode 100644 requirements.txt diff --git a/EVENTS/SimpleWaves/SimpleWaves.cpp b/EVENTS/SimpleWaves/SimpleWaves.cpp index e69de29b..49b68e0b 100644 --- a/EVENTS/SimpleWaves/SimpleWaves.cpp +++ b/EVENTS/SimpleWaves/SimpleWaves.cpp @@ -0,0 +1,549 @@ +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: JustinBonus + +#include "SimpleWaves.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include "slidingstackedwidget.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// #include +#include "QVector3D" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// Trying out +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// #include + +SimpleWaves::SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget *parent) + : SimCenterAppWidget(parent), theRandomVariablesContainer(theRandomVariableIW) +{ + +} + +SimpleWaves::~SimpleWaves() +{ + +} + + +void SimpleWaves::executeBackendScript() +{ + // + // Update JSON input file and then pass arguments to a python script. Runs script to prepare case directory. + // Python scripts hosted remotely by SimCenterBackendApplications/modules/createEVENT/* + // + + updateJSON(); + QString scriptName = "SimpleWaves.py"; // "setup_case.py"; + QString scriptPath = pyScriptsPath() + QDir::separator() + scriptName; + QString templatePath = templateDictDir(); + QString jsonPath = caseDir() + QDir::separator() + "constant" + QDir::separator() + "simCenter" + QDir::separator() + "input"; + QString outputPath = caseDir(); + if (QFileInfo(scriptPath).exists()) + { + QString program = SimCenterPreferences::getInstance()->getPython(); + QStringList arguments; arguments << scriptPath << jsonPath << templatePath << outputPath; + QProcess *process = new QProcess(this); + process->start(program, arguments); + process->waitForFinished(-1); + process->close(); + } + else + { + qDebug() << "Cannot find the script path: " << scriptPath; + } + return; +} + +void SimpleWaves::readCaseData() +{ + //Write it to JSON becase it is needed for the mesh generation before the final simulation is run. + //In future only one JSON file in temp.SimCenter directory might be enough + QString inputFileName = "SimpleWaves.json"; + QString inputFilePath = caseDir() + QDir::separator() + + "constant" + QDir::separator() + + "simCenter" + QDir::separator() + + "input" + QDir::separator() + + inputFileName; + QFile jsonFile(inputFilePath); + if (!jsonFile.open(QFile::ReadOnly | QFile::Text)) + { + qDebug() << "Cannot find/read input-file path: " << inputFilePath; + return; + } + + QString val = jsonFile.readAll(); + QJsonDocument doc = QJsonDocument::fromJson(val.toUtf8()); + QJsonObject jsonObject = doc.object(); + inputFromJSON(jsonObject); + jsonFile.close(); + removeOldFiles(); +} + +void SimpleWaves::onBrowseCaseDirectoryButtonClicked(void) +{ + // QString fileName = QFileDialog::getExistingDirectory(this, tr("Open Directory"), caseDir(), + // QFileDialog::ShowDirsOnly + // | QFileDialog::DontResolveSymlinks); + // QDir newCaseDir(fileName); + // if (!newCaseDir.exists()) + // { + // return; + // } + // caseDirectoryPathWidget->setText(fileName); + + // if (!isCaseConfigured()) + // { + // setupCase(); + // return; + // } + + // // Need to have JSON (SimpleWaves.json) in LocalWorkDir/SimpleWaves/constant/simCenter/input + // readCaseData(); + // caseDirectoryPathWidget->setText(fileName); + // return; +} + +void SimpleWaves::clear(void) +{ + +} + +bool SimpleWaves::outputCitation(QJsonObject &jsonObject) +{ + QJsonObject citeClaymore; + QJsonObject citeClaymoreUW; + + citeClaymore["citation"] = "Wang, Xinlei and Qiu Yuxing, et al. (2020). “A massively parallel and scalable multi-GPU material point method.”"; + citeClaymore["description"] = "The Multi-GPU Material Point Method software, claymore, which is the predeccesor to ClaymoreUW SimpleWaves. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It is designed primarily for back-end computer graphics usage."; + citeClaymoreUW["citation"] = "Bonus, Justin (2023). “Evaluation of Fluid-Driven Debris Impacts in a High-Performance Multi-GPU Material Point Method.” PhD thesis, University of Washington, Seattle, WA."; + citeClaymoreUW["description"] = "The ClaymoreUW Multi-GPU Material Point Method software developed in this PhD thesis is the engineering refactor of the claymore SimpleWaves software. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It features higher computational precision, validated accuracy in multiple debris-fluid-structure interaction problems, new algorithms (ASFLIP, F-Bar antilocking), an expanded user-interface, and improved material behavior."; + jsonObject["claymore"] = citeClaymore; + jsonObject["ClaymoreUW"] = citeClaymoreUW; + return true; +} + +bool SimpleWaves::inputFromJSON(QJsonObject &jsonObject) +{ + this->clear(); + + QString newCaseDirectoryPath(jsonObject["caseDirectoryPath"].toString()); + + if (newCaseDirectoryPath.isEmpty()) { + qDebug() << "SimpleWaves::inputFromJSON: newCaseDirectoryPath is empty in JSON input."; + return false; + } + + QDir newCaseDir(newCaseDirectoryPath); + if (!newCaseDir.exists()) { + qDebug() << "SimpleWaves::inputFromJSON: newCaseDir does not exist in folder structure: " << newCaseDirectoryPath; + return false; + } + + if (newCaseDirectoryPath != caseDirectoryPathWidget->text()) { + caseDirectoryPathWidget->setText(newCaseDirectoryPath); + } + + caseDirectoryPathWidget->setText(jsonObject["caseDirectoryPath"].toString()); + + return true; +} + +bool SimpleWaves::outputToJSON(QJsonObject &jsonObject) +{ + jsonObject["EventClassification"] = "Hydro"; // Important for workflow (Earthquake vs Wind vs Hydro, etc.) + jsonObject["type"] = "SimpleWaves"; + + jsonObject["Application"] = "SimpleWaves"; // For accessing SimCenterBackendApplications/applications/createEVENTS/{Application}/*.py ? + jsonObject["subtype"] = "SimpleWaves"; + + return true; +} + +bool SimpleWaves::outputAppDataToJSON(QJsonObject &jsonObject) { + + // + // Per API, need to add name of application to be called in Application + // and all data to be used in ApplicationData + // + + // jsonObject["EventClassification"] = "Hydro"; + // jsonObject["Application"] = "SimpleWaves"; + // QJsonObject dataObj; + // jsonObject["ApplicationData"] = dataObj; + + // jsonObject["programFile"] = "SimpleWaves"; // <- ClaymoreUW SimpleWaves executable filename on remote machine. Can be changed depending on compiled optimizations, versions, digital twin, etc. + // jsonObject["maxRunTime"] = "00:05:00"; // <- Maximum run time for the simulation, timeout if exceeded + return true; +} +bool SimpleWaves::inputAppDataFromJSON(QJsonObject &jsonObject) { + + Q_UNUSED(jsonObject); + return true; +} + + +bool SimpleWaves::copyFiles(QString &destDir) { + // + // Copy the files in the case directory to the destination directory + // This is the directory where the simulations will be run / staged + // Should pull together any files needed for the simulation, e.g. specified input files + // + + executeBackendScript(); + QString caseName = "SimpleWaves"; + QString destDirCase = destDir + QDir::separator() + caseName; + QDir destDirCaseDir(destDirCase); + if (!destDirCaseDir.exists()) + { + destDirCaseDir.mkpath("."); // Make the directory if it doesn't exist + } + bool result = this->copyPath(caseDir(), destDirCase, false); // False means don't copy the directory itself, just the contents + if (!result) + { + QString errorMessage; errorMessage = "SimpleWaves - failed to copy files in: " + caseDir() + " to: " + destDirCase; + emit sendFatalMessage(errorMessage); + qDebug() << errorMessage; + return false; + } + + // + // Copy files from all the major sub-widgets + // + + if (simpleWavesSettings->copyFiles(destDir) == false) + { + qDebug() << "SimpleWaves - failed to copy settings files"; + return false; + } + if (simpleWavesBodies->copyFiles(destDir) == false) + { + qDebug() << "SimpleWaves - failed to copy bodies files"; + return false; + } + // if (simpleWavesBoundaries->copyFiles(destDir) == false) + // { + // qDebug() << "SimpleWaves - failed to copy boundaries files"; + // return false; + // } + if (simpleWavesSensors->copyFiles(destDir) == false) + { + qDebug() << "SimpleWaves - failed to copy sensors files"; + return false; + } + if (simpleWavesOutputs->copyFiles(destDir) == false) + { + qDebug() << "SimpleWaves - failed to copy outputs files"; + return false; + } + // if (simpleWavesResults->copyFiles(destDir) == false) + // { + // qDebug() << "SimpleWaves - failed to copy results files"; + // return false; + // } + + return true; + } + + +bool SimpleWaves::cleanCase() +{ + // + // Remove the primary folders and log file within the case directory recursively + // + + QDir zeroDir(caseDir() + QDir::separator() + "0"); + QDir constDir(caseDir() + QDir::separator() + "constant"); + QDir systemDir(caseDir() + QDir::separator() + "system"); + zeroDir.removeRecursively(); + constDir.removeRecursively(); + systemDir.removeRecursively(); + QFile logFile(caseDir() + QDir::separator() + "log.txt"); + if (logFile.exists()) { + logFile.remove(); + } + return true; +} + +bool SimpleWaves::removeOldFiles() +{ + // + // Remove extra files if they exist in case directory's "0" folder + // + + auto removeFile = [this](QString filePath) { + QFile file(caseDir() + QDir::separator() + "0" + QDir::separator() + filePath); + if (file.exists()) { + qDebug() << "Removing old file: " << filePath; + file.remove(); + } + }; + removeFile(caseDir() + QDir::separator() + "0" + QDir::separator() + "oldFile"); + return true; +} + +bool SimpleWaves::setupCase() +{ + cleanCase(); + QDir targetDir(caseDir()); + if (!targetDir.exists()) + { + targetDir.mkpath(caseDir()); + } + targetDir.mkpath("0"); + targetDir.mkpath("constant"); + targetDir.mkpath("constant/geometry"); + targetDir.mkpath("constant/simCenter"); + targetDir.mkpath("constant/simCenter/output"); + targetDir.mkpath("constant/simCenter/input"); + targetDir.mkpath("constant/boundaryData"); + targetDir.mkpath("constant/boundaryData/inlet"); + targetDir.mkpath("system"); + + // Write setup files using the backend python script + executeBackendScript(); + return true; +} + +// From WE-UQ EmptyDomainCFD +QVector> SimpleWaves::readTxtData(QString fileName) +{ + int colCount = 0; + QVector> data; + QFile inputFileTest(fileName); + if (inputFileTest.open(QIODevice::ReadOnly)) + { + QTextStream in(&inputFileTest); + + while (!in.atEnd()) + { + QString line = in.readLine(); + QStringList fields = line.split(" "); + colCount = fields.size(); + break; + } + inputFileTest.close(); + } + + for (int i=0; i < colCount; i++) + { + QVector row; + data.append(row); + } + + int count = 0; + QFile inputFile(fileName); + if (inputFile.open(QIODevice::ReadOnly)) + { + QTextStream in(&inputFile); + while (!in.atEnd()) + { + QString line = in.readLine(); + QStringList fields = line.split(" "); + for (int i=0; i < colCount; i++) + { + data[i].append(fields[i].toDouble()); + } + } + inputFile.close(); + } + + return data; +} + +bool SimpleWaves::isCaseConfigured() +{ + QDir zeroDir(caseDir() + QDir::separator() + "0"); + QDir constDir(caseDir() + QDir::separator() + "constant"); + QDir systemDir(caseDir() + QDir::separator() + "system"); + // QFile contrlDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "controlDict"); + // QFile blockDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "blockMeshDict"); + // QFile snappyDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "snappyHexMeshDict"); + + // //Better if we check other files too, for now these are enougg to run a mesh + // return zeroDir.exists() && constDir.exists() && systemDir.exists() && + // contrlDict.exists() && blockDict.exists() && snappyDict.exists(); + return zeroDir.exists() && constDir.exists() && systemDir.exists(); +} + +QString SimpleWaves::caseDir() +{ + return caseDirectoryPathWidget->text(); +} + +QString SimpleWaves::pyScriptsPath() +{ + QString backendAppDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() + + QString("applications") + QDir::separator() + QString("createEVENT") + QDir::separator() + + QString("SimpleWaves"); + + QString backendAppDir = QString("./") + QDir::separator() + + QString("SimpleWaves"); + return backendAppDir; +} + +// Probably not needed for anything but OpenFOAM +QString SimpleWaves::templateDictDir() +{ + QString templateSubFolder = QString("templateOF10Dicts");// "templateSimpleWavesDicts"; + QString templateDictsDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() + + QString("applications") + QDir::separator() + + QString("createEVENT") + QDir::separator() + + QString("SimpleWaves") + QDir::separator() + + templateSubFolder; + return templateDictsDir; +} + +QString SimpleWaves::simulationType() +{ + return QString("SimpleWaves"); // Yet to support turbulence models in SimpleWaves, so its just "SimpleWaves" (i.e. DNS) +} + +SC_ResultsWidget* SimpleWaves::getResultsWidget(QWidget *parent) +{ + // theTabWidget.setCurrentIndex(theTabWidget.indexOf("Results")); + // Set theTabWidget to show the "Results" tab using its text + if (simpleWavesResults) + { + theTabWidget->setCurrentIndex(theTabWidget->count() - 1); + } + else + { + QWidget* resultsWidget = new QWidget(); + QVBoxLayout* resultsLayout = new QVBoxLayout(); + resultsWidget->setLayout(resultsLayout); + simpleWavesResults = new ResultsSimpleWaves(this); + + resultsLayout->addWidget(simpleWavesResults); + resultsLayout->addStretch(); + theTabWidget->addTab(resultsWidget, QIcon(QString(":/icons/flag-black.svg")), "Results"); + theTabWidget->setCurrentIndex(theTabWidget->count() - 1); + } + + statusMessage("HydroUQ EVENTS SimpleWaves - Get results widget for the EVT to allow us to post-process the downloaded results (or locally saved results) for visualization."); + return simpleWavesResults; +} + +void SimpleWaves::importMainDomainJsonFile(QJsonObject &jsonObject) +{ + // openFoamVersion->setCurrentText(jsonObject["OpenFoamVersion"].toString()); + // geometry->inputFromJSON(jsonObject); + // snappyHexMesh->inputFromJSON(jsonObject); + // windCharacteristics->inputFromJSON(jsonObject); + // boundaryConditions->inputFromJSON(jsonObject); + // turbulenceModeling->inputFromJSON(jsonObject); + // numericalSetup->inputFromJSON(jsonObject); +} + diff --git a/EVENTS/SimpleWaves/SimpleWaves.h b/EVENTS/SimpleWaves/SimpleWaves.h index e69de29b..c88ad42a 100644 --- a/EVENTS/SimpleWaves/SimpleWaves.h +++ b/EVENTS/SimpleWaves/SimpleWaves.h @@ -0,0 +1,149 @@ +#ifndef SIMPLE_WAVES_H +#define SIMPLE_WAVES_H + +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Author: JustinBonus +// Date: 5/2024 + +#include + +// #include + +#include +// Forward declaration +class InputWidgetParameters; +class RandomVariablesContainer; +class LineEditRV; + +// class SettingsSimpleWaves; +// class BodiesSimpleWaves; +// class BoundariesSimpleWaves; +// class SensorsSimpleWaves; +// class OutputsSimpleWaves; +// class ResultsSimpleWaves; + +class SC_DoubleLineEdit; +class SC_IntLineEdit; + +class QGridLayout; +class QVBoxLayout; +class QHBoxLayout; + +class QComboBox; +class QSpinBox; +class QLineEdit; +class QTabWidget; + +class QGroupBox; +class QPushButton; +class QCheckBox; +class QFormLayout; +class QLabel; +class SimpleWaves : public SimCenterAppWidget +{ + Q_OBJECT + +public: + explicit SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget *parent = 0); + // SimpleWaves( QWidget *parent = 0); + ~SimpleWaves(); + +// friend class ResultsSimpleWaves; // Allow ResultsSimpleWaves to access private members. TODO: use a better vis architecture + + bool inputFromJSON(QJsonObject &rvObject) override; + bool outputToJSON(QJsonObject &rvObject) override; + bool outputAppDataToJSON(QJsonObject &rvObject) ; + bool inputAppDataFromJSON(QJsonObject &rvObject); + bool copyFiles(QString &dirName) override; + bool outputCitation(QJsonObject &jsonObject) override; + +// bool initialize(); +// bool isInitialize(); + + bool setupCase(); + bool cleanCase(); + bool removeOldFiles(); + bool isCaseConfigured(); + void readCaseData(); + +// void importMainDomainJsonFile(QJsonObject &rvObject); +// QVector> readTxtData(QString fileName); + + void executeBackendScript(); + void updateJSON(); + QString caseDir(); + QString templateDictDir(); + QString pyScriptsPath(); + QString simulationType(); + // QString foamDictsPath(); // For OpenFOAM from WE-UQ, not SimpleWaves + + SC_ResultsWidget* getResultsWidget(QWidget *parent) override; // For vis of output data results + +signals: + +public slots: + void clear(void) override; + void onBrowseCaseDirectoryButtonClicked(void); + +private: + QHBoxLayout *mainWindowLayout; + QGridLayout *mainLayout; +// SettingsSimpleWaves *mpmSettings; +// BodiesSimpleWaves *mpmBodies; +// BoundariesSimpleWaves *mpmBoundaries; +// SensorsSimpleWaves *mpmSensors; +// OutputsSimpleWaves *mpmOutputs; +// ResultsSimpleWaves *mpmResults; + + RandomVariablesContainer *theRandomVariablesContainer; + QStringList varNamesAndValues; + + QString workingDirPath; + QLineEdit *caseDirectoryPathWidget; + QGroupBox *caseDirectoryGroup; + QGridLayout *caseDirectoryLayout; + QTabWidget *theTabWidget; + // QVBoxLayout *visWindowLayout; + // QGroupBox *visWindowGroup; + // QVBoxLayout *inputWindowLayout; + // QGroupBox *inputWindowGroup; +// bool caseInitialized = false; + QWebEngineView* m_pWebView; +}; + +#endif // SIMPLE_WAVES_H diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..2ef04e82 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +matplotlib +xlrd +numpy>=1.16.5; python_version>"3.0" +pandas>=1.0.1; python_version>"3.0" +chardet +scipy +sympy +welib From cce0c5aa6f27c5aee528cabf2ab0edcce2c3c882 Mon Sep 17 00:00:00 2001 From: JustinBonus Date: Tue, 14 May 2024 10:58:59 -0700 Subject: [PATCH 3/5] Add in functions and general process for getting wave kinematics and forces for profiles or recorder points for Jonswap spectrum in SimpleWaves EVT --- EVENTS/SimpleWaves/Ex1_WaveKinematics.py | 121 ++++++++++ EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py | 45 ++++ EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py | 71 ++++++ EVENTS/SimpleWaves/Ex4_WaveLoads.py | 176 ++++++++++++++ EVENTS/SimpleWaves/SimpleWaves.cpp | 263 +++++++++------------ 5 files changed, 528 insertions(+), 148 deletions(-) create mode 100644 EVENTS/SimpleWaves/Ex1_WaveKinematics.py create mode 100644 EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py create mode 100644 EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py create mode 100644 EVENTS/SimpleWaves/Ex4_WaveLoads.py diff --git a/EVENTS/SimpleWaves/Ex1_WaveKinematics.py b/EVENTS/SimpleWaves/Ex1_WaveKinematics.py new file mode 100644 index 00000000..a299ee21 --- /dev/null +++ b/EVENTS/SimpleWaves/Ex1_WaveKinematics.py @@ -0,0 +1,121 @@ +""" +Plot the wave kinematics (elevation, velocity, acceleration) for linear waves +Different locations, times and superposition of frequencies can be used. +""" +import numpy as np +import matplotlib.pyplot as plt +from welib.tools.figure import defaultRC; defaultRC(); +from welib.tools.colors import python_colors +from welib.hydro.wavekin import elevation2d, wavenumber, kinematics2d + + +fig,axes = plt.subplots(2, 2, sharey=False, figsize=(6.4,4.8)) # (6.4,4.8) +fig.subplots_adjust(left=0.10, right=0.95, top=0.91, bottom=0.09, hspace=0.29, wspace=0.46) +plt.suptitle('Hydro - Wave kinematics') + + +g = 9.81 # gravity [m/s^2] +h = 30. # water depth [m] + +# --- (Top Left) Example for one frequency, one point, multiple times +a = 3 # wave peak amplitude [m] +x, z = 0, 0 # position where kinematics are evaluated [m] +T = 12. # period [s] +eps = 0 # phase shift [rad] +f = 1./T +k = wavenumber(f, h, g) +time = np.arange(0,2*T,T/101) +# Wave kinematics +vel,acc = kinematics2d(a, f, k, eps, h, time, z, x) +eta = elevation2d(a, f, k, eps, time, x) + +# Plot +ax=axes[0,0] +ax.plot(time, eta , label=r'Elevation [m]') +ax.plot(time, vel , label=r'Velocity [m/s]') +ax.plot(time, acc , label=r'Acceleration [m$^2$/s]') +ax.set_xlabel('Time [s]') +ax.set_ylabel('Kinematics') +ax.legend(fontsize=8, loc='lower center') +ax.set_title('One frequency') + + +# --- (Bottom Left) Example for one frequencies, multiple points(1d array), multiple times +a = np.array([3, ]) # wave peak amplitude [m] +T = np.array([12.]) # period [s] +eps = np.array([0 ]) # phase shift [rad] +z = np.linspace(-h, 0, 10) # position where kinematics are evaluated +x = z*0 +f = 1./T +k = wavenumber(f, h, g) +time = np.linspace(0,2*T[0]/2,5) +vel,acc = kinematics2d(a, f, k, eps, h, time, z, x) +#eta = elevation2d(a, f, k, eps, time, x) +ax=axes[1,0] +sT = ['0','T/4','T/2','3T/4'] +for it,t in enumerate(time[:-1]): + ax.plot(vel[:,it], z, ['-','-','-','--'][it], c=python_colors(it), label='vel, t={:}'.format(sT[it])) +for it,t in enumerate(time[:-1]): + ax.plot(acc[:,it], z, ['o','.','.','.'][it], c=python_colors(it), label='acc, t={:}'.format(sT[it])) +ax.set_ylabel('Water depth [m]') +ax.set_xlabel('Velocity and acceleration') +ax.legend(fontsize=8, ncol=2, loc='lower center') + + +# --- (Top Right) Example for multiple frequencies, one point, multiple times +a = np.array([1., 3., 5., 0.5]) # wave peak amplitude [m] +T = np.array([20., 12.,9., 3.]) # period [s] +eps = np.array([np.pi/4, 0, np.pi/2, 0]) # phase shift [rad] +x, z = 0, 0 # position where kinematics are evaluated +f = 1./T +k = wavenumber(f, h, g) +time = np.arange(0,2*T[0],T[0]/101) +vel,acc = kinematics2d(a, f, k, eps, h, time, z, x) +eta = elevation2d(a, f, k, eps, time, x) + +# Plot +ax=axes[0,1] +ax.plot(time, eta , label=r'Elevation [m]') +ax.plot(time, vel , label=r'Velocity [m/s]') +ax.plot(time, acc , label=r'Acceleration [m$^2$/s]') +ax.set_xlabel('Time [s]') +ax.set_ylabel('Kinematics') +ax.legend(fontsize=8, loc='lower center') +ax.tick_params(direction='in') +ax.set_ylim([-8,8]) +ax.set_title('Multiple frequencies') + + +# --- (Bottom Left) multiple frequencies, multiple points (2d array), multiple times +a = np.array([1., 3., 5., 0.5]) # wave peak amplitude [m] +T = np.array([20., 12.,9., 3.]) # period [s] +eps = np.array([np.pi/4, 0, np.pi/2, 0]) # phase shift [rad] +vz = np.linspace(-h, 0, 2) # position where kinematics are evaluated +vx = np.linspace(-10,10,3) +X,Z = np.meshgrid(vx,vz) +f = 1./T +k = wavenumber(f, h, g) +time = np.arange(0,2*T[0],T[0]/101) +vel,acc = kinematics2d(a, f, k, eps, h, time, Z, X) +#eta = elevation2d(a, f, k, eps, time, x) + +# --- Plot +ax=axes[1,1] +for i,z in enumerate(vz): + for j,x in enumerate(vx): + ax.plot(time, vel[i,j,:], ['--','-',':'][j], c=python_colors(i), label='z={:.0f} x={:.0f}'.format(z,x)) +ax.set_ylabel('Velocity [m/s]') +ax.set_xlabel('Time [s]') +ax.legend(fontsize=8, loc='lower center', ncol=2) +ax.set_ylim([-8,8]) +ax.tick_params(direction='in') + + + +if __name__=="__main__": + plt.show() +if __name__=="__test__": + pass +if __name__=="__export__": + from welib.tools.repo import export_figs_callback + export_figs_callback(__file__) diff --git a/EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py b/EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py new file mode 100644 index 00000000..3f8867cd --- /dev/null +++ b/EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py @@ -0,0 +1,45 @@ +""" +Plot the JONSWAP spectrum for a given sea state +""" +import numpy as np +from welib.hydro.spectra import jonswap +import matplotlib.pyplot as plt + +# --- Parameters +t = np.arange(0,3600.1,1) # time vector [s] +dt = t[1]-t[0] # timestep [s] +Hs = 8.1 # Significant wave height [m] +Tp = 12.7 # Peak period [s] + +# --- Derived parameters +df = 1./np.max(t) # Step size for frequency +fMax = (1./dt)/2 # Highest frequency +freq = np.arange(df, fMax+df/2, df) + +# --- Spectrum and amplitude +S = jonswap(freq, Hs, Tp) # Spectral density [m^2.s] +ap = np.sqrt(2*S*df) # Wave amplitude [m] + +# Find location of maximum energy +iMax = np.argmax(S) + +# --- Plots +fig,ax = plt.subplots(1, 1, sharey=False, figsize=(6.4,4.8)) # (6.4,4.8) +fig.subplots_adjust(left=0.12, right=0.95, top=0.95, bottom=0.11, hspace=0.20, wspace=0.20) +ax.plot(freq, S) +ax.plot(freq[iMax], S[iMax], 'ko') +ax.set_xlabel('Frequency [Hz]') +ax.set_ylabel(r'Spectral density [m^2 s]') +ax.set_title('Hydro - Jonswap spectrum') +ax.tick_params(direction='in') + + +if __name__=="__main__": + plt.show() +if __name__=="__test__": + np.testing.assert_almost_equal(S[iMax], 113.8770176) +if __name__=="__export__": + from welib.tools.repo import export_figs_callback + export_figs_callback(__file__) + + diff --git a/EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py b/EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py new file mode 100644 index 00000000..ad11bf5f --- /dev/null +++ b/EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py @@ -0,0 +1,71 @@ +""" +Generate wave time series based on the Jonswap spectrum +""" +import numpy as np +import matplotlib.pyplot as plt +from welib.hydro.spectra import jonswap +from welib.hydro.wavekin import elevation2d, wavenumber +from welib.tools.spectral import fft_wrap +from numpy.random import uniform, seed +seed(10) + + +# --- Parameters +# t = np.linspace(0,600,601) # time vector [s] +t = np.linspace(0,3600,3601) # time vector [s] +Hs = 8.1 # Significant wave height [m] +Tp = 12.7 # Peak period [s] +h = 30. # Water depth [m] +g = 9.80665 # Gravity[m/s2] + +# --- Jonswap spectrum +dt = t[1]-t[0] # timestep [s] +df = 1/np.max(t) # step size for frequency +fHighCut = 1/(dt)/2. # Highest frequency in calculations +freq = np.arange(df, fHighCut, df) +S = jonswap(freq, Hs, Tp=Tp, g=9.80665) + +# --- Solve dispersion relation +k = wavenumber(freq, h, g) + +# --- Compute wave elevation based on amplitudes and random phases +eps = uniform(0,2*np.pi,len(freq)) # random phases between 0 and 2pi +a = np.sqrt(2*S*df) # wave amplitudes based on spectrum +x = 0 # longitudinal distance where wave is evaluated [m] +eta = elevation2d(a, freq, k, eps, t, x) + +# --- Compute FFT of wave elevation +f_fft, S_fft, Info = fft_wrap(t, eta, output_type='PSD', averaging='none') + + +# --- Plots +fig,axes = plt.subplots(2, 1, sharey=False, figsize=(6.4,4.8)) # (6.4,4.8) +fig.subplots_adjust(left=0.12, right=0.95, top=0.95, bottom=0.11, hspace=0.30, wspace=0.20) + +ax=axes[0] +ax.plot(t, eta) +ax.tick_params(direction='in') +ax.autoscale(enable=True, axis='both', tight=True) +ax.set_xlabel('Time [s]') +ax.set_ylabel(r'Wave elevation [m]') +ax.set_title('Hydro - wave generation') + +ax=axes[1] +ax.plot(f_fft, S_fft, '-', label='Generated') +ax.plot(freq, S , 'k', label='Jonswap') +ax.legend() +ax.set_xlabel('Frequency [Hz]') +ax.set_ylabel(r'Spectral density [m$^2$ s]') +ax.tick_params(direction='in') +ax.autoscale(enable=True, axis='both', tight=True) + + +if __name__=="__main__": + plt.show() +if __name__=="__test__": + pass +if __name__=="__export__": + from welib.tools.repo import export_figs_callback + export_figs_callback(__file__) + + diff --git a/EVENTS/SimpleWaves/Ex4_WaveLoads.py b/EVENTS/SimpleWaves/Ex4_WaveLoads.py new file mode 100644 index 00000000..6d35ecf8 --- /dev/null +++ b/EVENTS/SimpleWaves/Ex4_WaveLoads.py @@ -0,0 +1,176 @@ +""" +Compute inline/total hydrodynamic force and moments on a monopile using Morison's equation +""" +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from fractions import Fraction +import matplotlib as mpl +# Local +from welib.tools.figure import defaultRC; defaultRC(); +from welib.tools.colors import python_colors +from welib.hydro.wavekin import * +from welib.hydro.morison import * + + +# --- Parameters +g = 9.81 # gravity [m/s^2] +h = 30. # water depth [m] +rho = 1025 # water density +D = 6 # monopile diameter [m] +CD = 1 # given +CM = 2 # +a = 3 # wave peak amplitude [m] +T = 12. # period [s] +eps = 0 # phase shift [rad] +f = 1./T +k = wavenumber(f, h, g) + +nz = 30 # number of points used in the z direction to compute loads +z_ref = -h # reference point for moment calculation + +# --------------------------------------------------------------------------------} +# --- Inline force and moments as function of time, with or without Wheeler stretching +# --------------------------------------------------------------------------------{ +time = np.linspace(0,T,9) + +fig1,axes1 = plt.subplots(2, 4, sharex=True, sharey=True, figsize=(12.8,4.8)) # (6.4,4.8) +fig1.subplots_adjust(left=0.05, right=0.99, top=0.95, bottom=0.09, hspace=0.26, wspace=0.11) + +fig2,axes2 = plt.subplots(2, 4, sharex=True, sharey=True, figsize=(12.8,4.8)) # (6.4,4.8) +fig2.subplots_adjust(left=0.05, right=0.99, top=0.95, bottom=0.09, hspace=0.26, wspace=0.11) + +XLIM =[-75,75] # For inline force +XLIMM=[-2500,2500] # For inline moment + +for it, t in enumerate(time[:-1]): + # Wave kinematics + eta = elevation2d(a, f, k, eps, t, x=0) + z = np.linspace(-h, eta, nz) + u, du = kinematics2d(a, f, k, eps, h, t, z, Wheeler=True, eta=eta) + u0, du0 = kinematics2d(a, f, k, eps, h, t, z) + # Wave loads with wheeler + p_tot = inline_load(u, du, D, CD , CM , rho) + p_inertia = inline_load(u, du, D, CD*0, CM , rho) + p_drag = inline_load(u, du, D, CD , CM*0, rho) + dM = p_tot * (z-z_ref) # [Nm/m] + + # Wave loads without Wheeler + p_tot0 = inline_load(u0, du0, D, CD , CM , rho) + p_inertia0= inline_load(u0, du0, D, CD*0, CM , rho) + p_drag0 = inline_load(u0, du0, D, CD , CM*0, rho) + dM0 = p_tot0* (z-z_ref) # [Nm/m] + + + # Plot inline force + ax=axes1[int(it/4),np.mod(it,4)] + ax.plot(p_inertia/1000,z, '-', c=python_colors(0), label = r'$f_{inertia}$') + ax.plot(p_drag/1000 ,z, '-', c=python_colors(3), label = r'$f_{drag}$') + ax.plot(p_tot/1000 ,z, 'k-' , label = r'$f_{tot}$') + ax.plot(p_inertia0/1000,z, '+', c=python_colors(0)) + ax.plot(p_drag0/1000 ,z, '+', c=python_colors(3)) + ax.plot(p_tot0/1000 ,z, 'k+' ) + ax.set_title('t/T={}'.format(Fraction(t/T))) + if it==0: + ax.legend() + ax.plot(XLIM,[0,0],'k') + ax.plot(XLIM,[a,a],'k--') + ax.plot(XLIM,[-a,-a],'k--') + + # Plot inline moment + ax=axes2[int(it/4),np.mod(it,4)] + ax.plot(dM/1000 ,z, 'k-', label = r'$dM_{tot}$ with Wheeler') + ax.plot(dM0/1000 ,z, 'k+', label = r'$dM_{tot}$ no-correction') + ax.set_title('t/T={}'.format(Fraction(t/T))) + if it==0: + ax.legend() + ax.plot(XLIMM,[0,0],'k') + ax.plot(XLIMM,[a,a],'k--') + ax.plot(XLIMM,[-a,-a],'k--') + +axes1[0,0].set_xlim(XLIM) +axes1[0,0].set_ylim([-h,a+1]) +axes1[0,0].set_ylabel('Depth z [m]') +axes1[1,0].set_ylabel('Depth z [m]') +axes1[1,0].set_xlabel('Inline force [kN/m]') +axes1[1,1].set_xlabel('Inline force [kN/m]') +axes1[1,2].set_xlabel('Inline force [kN/m]') +axes1[1,3].set_xlabel('Inline force [kN/m]') + +axes2[0,0].set_xlim(XLIMM) +axes2[0,0].set_ylim([-h,a+1]) +axes2[0,0].set_ylabel('Depth z [m]') +axes2[1,0].set_ylabel('Depth z [m]') +axes2[1,0].set_xlabel('Inline moment [kNm/m]') +axes2[1,1].set_xlabel('Inline moment [kNm/m]') +axes2[1,2].set_xlabel('Inline moment [kNm/m]') +axes2[1,3].set_xlabel('Inline moment [kNm/m]') + +# --------------------------------------------------------------------------------} +# --- Integrated force and sea bed moment over a period +# --------------------------------------------------------------------------------{ +time = np.linspace(0,T,1000) + +veta = np.zeros(time.shape) +vF = np.zeros(time.shape) +vM = np.zeros(time.shape) +vF0 = np.zeros(time.shape) +vM0 = np.zeros(time.shape) + +XLIM =[-75,75] # For inline force +XLIMM=[-2500,2500] # For inline moment + +a=6 # NOTE: increased amplitude here to see Effect of Wheeler + +for it, t in enumerate(time): + # Wave kinematics + veta[it] = elevation2d(a, f, k, eps, t, x = 0) + z = np.linspace(-h, veta[it], nz) + u, du = kinematics2d(a, f, k, eps, h, t, z, Wheeler = True, eta = veta[it]) + u0, du0 = kinematics2d(a, f, k, eps, h, t, z) + # Wave loads with Wheeler + p_tot = inline_load(u, du, D, CD , CM , rho) + vF[it] = np.trapz(p_tot , z) # [N] + vM[it] = np.trapz(p_tot * (z-z_ref), z) # [Nm] + # Wave loads without Wheeler + p_tot0 = inline_load(u0, du0, D, CD , CM , rho) + vF0[it] = np.trapz(p_tot0 , z) # [N] + vM0[it] = np.trapz(p_tot0 * (z-z_ref), z) # [Nm] + +# Plot +fig, axes = plt.subplots(3, 1, sharex=True, figsize=(6.4,4.8)) # (6.4,4.8) +fig.subplots_adjust(left=0.12, right=0.95, top=0.95, bottom=0.11, hspace=0.14, wspace=0.20) +ax = axes[0] +ax.plot(time/T, veta,'k-') +ax.set_ylabel('Elevation [m]') +ax.grid(True) +ax = axes[1] +ax.plot(time/T, vF0/1e6 , label='no-correction') +ax.plot(time/T, vF /1e6,'k-', label='Wheeler') +ax.set_ylabel('Force [MN]') +ax.legend() +ax.grid(True) +ax = axes[2] +ax.plot(time/T, vM0/1e6 , label='no-correction') +ax.plot(time/T, vM /1e6,'k-', label='Wheeler') +ax.set_ylabel('Sea-bed moment [MNm]') +ax.set_xlabel('Dimensionless time t/T [-]') +ax.legend() +ax.grid(True) + +plt.suptitle('Hydro - Morison loads on monopile') + + + +if __name__ == '__main__': + plt.show() + +if __name__=="__test__": + pass + +if __name__ == '__export__': + plt.close(fig1) + plt.close(fig2) + from welib.tools.repo import export_figs_callback + export_figs_callback(__file__) + diff --git a/EVENTS/SimpleWaves/SimpleWaves.cpp b/EVENTS/SimpleWaves/SimpleWaves.cpp index 49b68e0b..41310897 100644 --- a/EVENTS/SimpleWaves/SimpleWaves.cpp +++ b/EVENTS/SimpleWaves/SimpleWaves.cpp @@ -130,6 +130,81 @@ SimpleWaves::SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget : SimCenterAppWidget(parent), theRandomVariablesContainer(theRandomVariableIW) { + + // Initialize member variables + dragCoefficient = new LineEditRV(randomVariables); + dragCoefficient->setText("2.1"); + + peakPeriod = new LineEditRV(randomVariables); + peakPeriod->setText("12.7"); + + significantWaveHeight = new LineEditRV(randomVariables); + significantWaveHeight->setText("8.1"); + + waterDepth = new LineEditRV(randomVariables); + waterDepth->setText("30.0"); + + recorderOriginX = new LineEditRV(randomVariables); + recorderOriginX->setText("0.0"); + + exposureCategory = new QComboBox(); + exposureCategory->addItem("B"); + exposureCategory->addItem("C"); + exposureCategory->addItem("D"); + + seed = new QSpinBox(); + seed->setMinimum(1); + seed->setMaximum(2147483647); + seed->setValue(500); + seed->setEnabled(false); + useSeed = new QRadioButton("Provide seed value"); + useSeed->setChecked(false); + + QFormLayout *parameters = new QFormLayout(); + + exposureCategory = new QComboBox(); + exposureCategory->addItem("B"); + exposureCategory->addItem("C"); + exposureCategory->addItem("D"); + + parameters->addRow(new QLabel(tr("Drag Coefficient")), dragCoefficient); + parameters->addRow(new QLabel(tr("Drag Area")), dragArea); + parameters->addRow(new QLabel(tr("Peak Period [s]")), peakPeriod); + parameters->addRow(new QLabel(tr("Significant Wave Height [m]")), significantWaveHeight); + parameters->addRow(new QLabel(tr("Water Depth [m]")), waterDepth); + parameters->addRow(new QLabel(tr("Recorder Horizontal Position [m]")), recorderOriginX); + parameters->addRow(new QLabel(tr("ASCE 7 Exposure Condition")), exposureCategory); +// parameters->addRow(new QLabel(tr("Gust Wind Speed (mph)")), gustWindSpeed); +// gustWindSpeed->setToolTip("3 sec gust speed at height of 10m (33ft)"); + // Add description label + modelDescription = + new QLabel(tr("This model provides wind speed time histories using a " + "power law for the wind profile based on the ASCE Exposure\n" + "Category and a discrete frequency function with FFT to " + "account for wind fluctuations (Wittig & Sinha, 1975)")); + //model_description_->setStyleSheet("QLabel { color : gray; }"); + + // Construct required layouts + QVBoxLayout* layout = new QVBoxLayout(); + QHBoxLayout* seedLayout = new QHBoxLayout(); + QHBoxLayout* parametersLayout = new QHBoxLayout(); + + // Add widgets to layouts and layouts to this + seedLayout->addWidget(useSeed); + seedLayout->addWidget(seed); + seedLayout->addStretch(); + parametersLayout->addLayout(parameters); + parametersLayout->addStretch(); + layout->addWidget(modelDescription); + layout->addLayout(parametersLayout); + layout->addLayout(seedLayout); + layout->addStretch(); + this->setLayout(layout); + + // Connect slots + connect(useSeed, &QRadioButton::toggled, this, + &WittigSinha::provideSeed); + } SimpleWaves::~SimpleWaves() @@ -148,9 +223,9 @@ void SimpleWaves::executeBackendScript() updateJSON(); QString scriptName = "SimpleWaves.py"; // "setup_case.py"; QString scriptPath = pyScriptsPath() + QDir::separator() + scriptName; - QString templatePath = templateDictDir(); - QString jsonPath = caseDir() + QDir::separator() + "constant" + QDir::separator() + "simCenter" + QDir::separator() + "input"; - QString outputPath = caseDir(); + QString templatePath = "."; + QString jsonPath = caseDir() + QDir::separator() //+ "input"; + QString outputPath = caseDir() + QDir::separator() //+ "output"; if (QFileInfo(scriptPath).exists()) { QString program = SimCenterPreferences::getInstance()->getPython(); @@ -167,31 +242,6 @@ void SimpleWaves::executeBackendScript() return; } -void SimpleWaves::readCaseData() -{ - //Write it to JSON becase it is needed for the mesh generation before the final simulation is run. - //In future only one JSON file in temp.SimCenter directory might be enough - QString inputFileName = "SimpleWaves.json"; - QString inputFilePath = caseDir() + QDir::separator() - + "constant" + QDir::separator() - + "simCenter" + QDir::separator() - + "input" + QDir::separator() - + inputFileName; - QFile jsonFile(inputFilePath); - if (!jsonFile.open(QFile::ReadOnly | QFile::Text)) - { - qDebug() << "Cannot find/read input-file path: " << inputFilePath; - return; - } - - QString val = jsonFile.readAll(); - QJsonDocument doc = QJsonDocument::fromJson(val.toUtf8()); - QJsonObject jsonObject = doc.object(); - inputFromJSON(jsonObject); - jsonFile.close(); - removeOldFiles(); -} - void SimpleWaves::onBrowseCaseDirectoryButtonClicked(void) { // QString fileName = QFileDialog::getExistingDirectory(this, tr("Open Directory"), caseDir(), @@ -219,19 +269,16 @@ void SimpleWaves::onBrowseCaseDirectoryButtonClicked(void) void SimpleWaves::clear(void) { + } bool SimpleWaves::outputCitation(QJsonObject &jsonObject) { - QJsonObject citeClaymore; QJsonObject citeClaymoreUW; - citeClaymore["citation"] = "Wang, Xinlei and Qiu Yuxing, et al. (2020). “A massively parallel and scalable multi-GPU material point method.”"; - citeClaymore["description"] = "The Multi-GPU Material Point Method software, claymore, which is the predeccesor to ClaymoreUW SimpleWaves. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It is designed primarily for back-end computer graphics usage."; citeClaymoreUW["citation"] = "Bonus, Justin (2023). “Evaluation of Fluid-Driven Debris Impacts in a High-Performance Multi-GPU Material Point Method.” PhD thesis, University of Washington, Seattle, WA."; citeClaymoreUW["description"] = "The ClaymoreUW Multi-GPU Material Point Method software developed in this PhD thesis is the engineering refactor of the claymore SimpleWaves software. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It features higher computational precision, validated accuracy in multiple debris-fluid-structure interaction problems, new algorithms (ASFLIP, F-Bar antilocking), an expanded user-interface, and improved material behavior."; - jsonObject["claymore"] = citeClaymore; - jsonObject["ClaymoreUW"] = citeClaymoreUW; + jsonObject["welib"] = citeClaymoreUW; return true; } @@ -263,11 +310,30 @@ bool SimpleWaves::inputFromJSON(QJsonObject &jsonObject) bool SimpleWaves::outputToJSON(QJsonObject &jsonObject) { - jsonObject["EventClassification"] = "Hydro"; // Important for workflow (Earthquake vs Wind vs Hydro, etc.) - jsonObject["type"] = "SimpleWaves"; - jsonObject["Application"] = "SimpleWaves"; // For accessing SimCenterBackendApplications/applications/createEVENTS/{Application}/*.py ? - jsonObject["subtype"] = "SimpleWaves"; + + + + bool result = true; + + jsonObject["type"] = "SimpleWaves"; + jsonObject["EventClassification"] = "Hydro"; + dragCoefficient->outputToJSON(jsonObject, QString("dragCoefficient")); + dragArea->outputToJSON(jsonObject, QString("dragArea")); + significantWaveHeight->outputToJSON(jsonObject, QString("significantWaveHeight")); + peakPeriod->outputToJSON(jsonObject, QString("peakPeriod")); + waterDepth->outputToJSON(jsonObject, QString("waterDepth")); + recorderOriginX->outputToJSON(jsonObject, QString("recorerOriginX")); + + jsonObject.insert("exposureCategory",exposureCategory->currentText()); + + if (useSeed->isChecked()) { + jsonObject.insert("seed", seed->value()); + } else { + jsonObject.insert("seed", "None"); + } + + return result; return true; } @@ -319,64 +385,10 @@ bool SimpleWaves::copyFiles(QString &destDir) { return false; } - // - // Copy files from all the major sub-widgets - // - - if (simpleWavesSettings->copyFiles(destDir) == false) - { - qDebug() << "SimpleWaves - failed to copy settings files"; - return false; - } - if (simpleWavesBodies->copyFiles(destDir) == false) - { - qDebug() << "SimpleWaves - failed to copy bodies files"; - return false; - } - // if (simpleWavesBoundaries->copyFiles(destDir) == false) - // { - // qDebug() << "SimpleWaves - failed to copy boundaries files"; - // return false; - // } - if (simpleWavesSensors->copyFiles(destDir) == false) - { - qDebug() << "SimpleWaves - failed to copy sensors files"; - return false; - } - if (simpleWavesOutputs->copyFiles(destDir) == false) - { - qDebug() << "SimpleWaves - failed to copy outputs files"; - return false; - } - // if (simpleWavesResults->copyFiles(destDir) == false) - // { - // qDebug() << "SimpleWaves - failed to copy results files"; - // return false; - // } - return true; } -bool SimpleWaves::cleanCase() -{ - // - // Remove the primary folders and log file within the case directory recursively - // - - QDir zeroDir(caseDir() + QDir::separator() + "0"); - QDir constDir(caseDir() + QDir::separator() + "constant"); - QDir systemDir(caseDir() + QDir::separator() + "system"); - zeroDir.removeRecursively(); - constDir.removeRecursively(); - systemDir.removeRecursively(); - QFile logFile(caseDir() + QDir::separator() + "log.txt"); - if (logFile.exists()) { - logFile.remove(); - } - return true; -} - bool SimpleWaves::removeOldFiles() { // @@ -402,66 +414,21 @@ bool SimpleWaves::setupCase() { targetDir.mkpath(caseDir()); } - targetDir.mkpath("0"); - targetDir.mkpath("constant"); - targetDir.mkpath("constant/geometry"); - targetDir.mkpath("constant/simCenter"); - targetDir.mkpath("constant/simCenter/output"); - targetDir.mkpath("constant/simCenter/input"); - targetDir.mkpath("constant/boundaryData"); - targetDir.mkpath("constant/boundaryData/inlet"); - targetDir.mkpath("system"); + // targetDir.mkpath("0"); + // targetDir.mkpath("constant"); + // targetDir.mkpath("constant/geometry"); + // targetDir.mkpath("constant/simCenter"); + // targetDir.mkpath("constant/simCenter/output"); + // targetDir.mkpath("constant/simCenter/input"); + // targetDir.mkpath("constant/boundaryData"); + // targetDir.mkpath("constant/boundaryData/inlet"); + // targetDir.mkpath("system"); // Write setup files using the backend python script executeBackendScript(); return true; } -// From WE-UQ EmptyDomainCFD -QVector> SimpleWaves::readTxtData(QString fileName) -{ - int colCount = 0; - QVector> data; - QFile inputFileTest(fileName); - if (inputFileTest.open(QIODevice::ReadOnly)) - { - QTextStream in(&inputFileTest); - - while (!in.atEnd()) - { - QString line = in.readLine(); - QStringList fields = line.split(" "); - colCount = fields.size(); - break; - } - inputFileTest.close(); - } - - for (int i=0; i < colCount; i++) - { - QVector row; - data.append(row); - } - - int count = 0; - QFile inputFile(fileName); - if (inputFile.open(QIODevice::ReadOnly)) - { - QTextStream in(&inputFile); - while (!in.atEnd()) - { - QString line = in.readLine(); - QStringList fields = line.split(" "); - for (int i=0; i < colCount; i++) - { - data[i].append(fields[i].toDouble()); - } - } - inputFile.close(); - } - - return data; -} bool SimpleWaves::isCaseConfigured() { @@ -485,9 +452,9 @@ QString SimpleWaves::caseDir() QString SimpleWaves::pyScriptsPath() { - QString backendAppDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() - + QString("applications") + QDir::separator() + QString("createEVENT") + QDir::separator() - + QString("SimpleWaves"); + // QString backendAppDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() + // + QString("applications") + QDir::separator() + QString("createEVENT") + QDir::separator() + // + QString("SimpleWaves"); QString backendAppDir = QString("./") + QDir::separator() + QString("SimpleWaves"); From 308ff9c8530fc8ccf011ff75570ea468161178ad Mon Sep 17 00:00:00 2001 From: JustinBonus Date: Wed, 15 May 2024 19:37:53 -0700 Subject: [PATCH 4/5] Initial update to add in a stochastic model EVT (from WE-UQ) and JONSWAP spectra python code --- EVENTS/HydroEventSelection.cpp | 107 +-- EVENTS/HydroEventSelection.h | 1 + EVENTS/SimpleWaves/SimpleWaves.cpp | 516 -------------- .../Ex1_WaveKinematics.py | 0 .../Ex2_Jonswap_spectrum.py | 0 .../Ex3_WaveTimeSeries.py | 0 .../Ex4_WaveLoads.py | 2 +- EVENTS/StochasticWaveModel/SimpleWaves.cpp | 655 ++++++++++++++++++ .../SimpleWaves.h | 111 +-- EVENTS/StochasticWaveModel/include/Jonswap.h | 137 ++++ .../include/StochasticWaveInput.h | 129 ++++ EVENTS/StochasticWaveModel/src/Jonswap.cpp | 188 +++++ .../src/StochasticWaveInput.cpp | 168 +++++ HydroEVENTS.pri | 10 +- WorkflowAppHydroUQ.cpp | 21 +- 15 files changed, 1435 insertions(+), 610 deletions(-) delete mode 100644 EVENTS/SimpleWaves/SimpleWaves.cpp rename EVENTS/{SimpleWaves => StochasticWaveModel}/Ex1_WaveKinematics.py (100%) rename EVENTS/{SimpleWaves => StochasticWaveModel}/Ex2_Jonswap_spectrum.py (100%) rename EVENTS/{SimpleWaves => StochasticWaveModel}/Ex3_WaveTimeSeries.py (100%) rename EVENTS/{SimpleWaves => StochasticWaveModel}/Ex4_WaveLoads.py (99%) create mode 100644 EVENTS/StochasticWaveModel/SimpleWaves.cpp rename EVENTS/{SimpleWaves => StochasticWaveModel}/SimpleWaves.h (60%) create mode 100644 EVENTS/StochasticWaveModel/include/Jonswap.h create mode 100644 EVENTS/StochasticWaveModel/include/StochasticWaveInput.h create mode 100644 EVENTS/StochasticWaveModel/src/Jonswap.cpp create mode 100644 EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp diff --git a/EVENTS/HydroEventSelection.cpp b/EVENTS/HydroEventSelection.cpp index 10f1cf2f..8cb8a1aa 100644 --- a/EVENTS/HydroEventSelection.cpp +++ b/EVENTS/HydroEventSelection.cpp @@ -62,7 +62,8 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include #include #include -#include +// #include +#include //********************************************************************************* // Main Hydro event //********************************************************************************* @@ -94,16 +95,19 @@ HydroEventSelection::HydroEventSelection(RandomVariablesContainer *theRandomVari eventSelection->addItem(tr("General Event (GeoClaw and OpenFOAM)")); eventSelection->addItem(tr("Digital Twin (GeoClaw and OpenFOAM)")); eventSelection->addItem(tr("Digital Twin (OpenFOAM and OpenSees)")); - // eventSelection->addItem(tr("Digital Twin (MPM)")); + eventSelection->addItem(tr("Digital Twin (MPM)")); // eventSelection->addItem(tr("Digital Twin (SPH)")); + eventSelection->addItem(tr("Stochastic Wave Loading")); + // Datatips for the different event types eventSelection->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); eventSelection->setItemData(0, "Shallow-Water-Equations -> Finite-Volume-Method (GeoClaw -> OpenFOAM) [Multi-CPU]", Qt::ToolTipRole); eventSelection->setItemData(1, "Shallow-Water-Equations -> Finite-Volume-Method -> Finite-Element-Analysis (GeoClaw -> OpenFOAM -> OpenSees) [Multi-CPU]", Qt::ToolTipRole); eventSelection->setItemData(2, "Finite-Volume-Method <-> Finite-Element-Analysis (OpenFOAM <-> OpenSees) [Multi-CPU]", Qt::ToolTipRole); - // eventSelection->setItemData(3, "Material-Point-Method (ClaymoreUW) [Multi-GPU]", Qt::ToolTipRole); + eventSelection->setItemData(3, "Material-Point-Method (ClaymoreUW) [Multi-GPU]", Qt::ToolTipRole); // eventSelection->setItemData(4, "Smoothed-Particle-Hydrodynamics (DualSPHysics) [CPU-GPU]", Qt::ToolTipRole); + eventSelection->setItemData(4, "Stochastic Wave Loading [CPU]", Qt::ToolTipRole); theSelectionLayout->addWidget(label); QSpacerItem *spacer = new QSpacerItem(50,10); @@ -121,14 +125,16 @@ HydroEventSelection::HydroEventSelection(RandomVariablesContainer *theRandomVari theGeoClawOpenFOAM = new GeoClawOpenFOAM(theRandomVariablesContainer); theWaveDigitalFlume = new WaveDigitalFlume(theRandomVariablesContainer); theCoupledDigitalTwin = new CoupledDigitalTwin(theRandomVariablesContainer); - // theMPM = new MPM(theRandomVariablesContainer); + theMPM = new MPM(theRandomVariablesContainer); // theSPH = new SPH(theRandomVariablesContainer); + theSimpleWaves = new StochasticWaveInput(theRandomVariablesContainer); theStackedWidget->addWidget(theGeoClawOpenFOAM); theStackedWidget->addWidget(theWaveDigitalFlume); theStackedWidget->addWidget(theCoupledDigitalTwin); - // theStackedWidget->addWidget(theMPM); + theStackedWidget->addWidget(theMPM); // theStackedWidget->addWidget(theSPH); + theStackedWidget->addWidget(theSimpleWaves); // --- @@ -140,16 +146,20 @@ HydroEventSelection::HydroEventSelection(RandomVariablesContainer *theRandomVari // Set the default event to select at boot-up. For now, it is MPM theStackedWidget->setCurrentIndex(3); theCurrentEvent = theMPM; + + // theStackedWidget->setCurrentIndex(0); + // theCurrentEvent = theGeoClawOpenFOAM; + // theCurrentEvent = theSimpleWaves; connect(eventSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(eventSelectionChanged(int))); connect(eventSelection,SIGNAL(currentTextChanged(QString)),this,SLOT(eventSelectionChanged(QString))); // WE-UQ - // QString stringForMPM = "Digital Twin (MPM)"; - // int indexForMPM = 3; - // eventSelection->setCurrentIndex(indexForMPM); - // eventSelection->setCurrentIndex(indexForMPM); - // theStackedWidget->setCurrentIndex(indexForMPM); - // theStackedWidget->setCurrentIndex(indexForMPM); + QString stringForMPM = "Digital Twin (MPM)"; + int indexForMPM = 3; + eventSelection->setCurrentIndex(indexForMPM); + eventSelection->setCurrentIndex(indexForMPM); + theStackedWidget->setCurrentIndex(indexForMPM); + theStackedWidget->setCurrentIndex(indexForMPM); // // QString stringForMPM = "Digital Twin (OpenFOAM and OpenSees)"; // // int indexForFOAMySees = 2; @@ -200,18 +210,18 @@ void HydroEventSelection::eventSelectionChanged(int arg1) theCurrentEvent = theCoupledDigitalTwin; theStackedWidget->setCurrentIndex(2); } - // else if (arg1 == 3) { - // MPM* theM = dynamic_cast(theMPM); + else if (arg1 == 3) { + MPM* theM = dynamic_cast(theMPM); - // theCurrentEvent = theM->isInitialize() ? theMPM - // : (theM->initialize() ? theMPM : nullptr); - // if (theCurrentEvent == nullptr) - // { - // qDebug() << "ERROR: Hydro-EventSelection failed while attempting to initialize the MPM Event, index: " << arg1; - // return; - // } - // theStackedWidget->setCurrentIndex(3); - // } + theCurrentEvent = theM->isInitialize() ? theMPM + : (theM->initialize() ? theMPM : nullptr); + if (theCurrentEvent == nullptr) + { + qDebug() << "ERROR: Hydro-EventSelection failed while attempting to initialize the MPM Event, index: " << arg1; + return; + } + theStackedWidget->setCurrentIndex(3); + } // else if (arg1 == 4) { // SPH* theM = dynamic_cast(theSPH); @@ -224,6 +234,10 @@ void HydroEventSelection::eventSelectionChanged(int arg1) // } // theStackedWidget->setCurrentIndex(4); // } + else if (arg1 == 4) { + theCurrentEvent = theSimpleWaves; + theStackedWidget->setCurrentIndex(4); + } else { qDebug() << "ERROR: Hydro-EventSelection selection-type unknown: " << arg1; return; @@ -252,16 +266,16 @@ void HydroEventSelection::eventSelectionChanged(const QString &arg1) theCurrentEvent = theCoupledDigitalTwin; theStackedWidget->setCurrentIndex(2); } - // else if(arg1 == "Digital Twin (MPM)" || arg1 == "MPM" || arg1 == "theMPM" || arg1 == "MPMDigitalTwin" || arg1 == "theMPMDigitalTwin" || arg1 == "MPM Digital Twin") { - // MPM* theM = dynamic_cast(theMPM); - // theCurrentEvent = theM->isInitialize() ? theMPM - // : ( theM->initialize() ? theMPM : nullptr ); - // if (!theCurrentEvent) { - // qDebug() << "ERROR: Hydro-EventSelection failed while attempting to initialize the MPM Event, label: " << arg1; - // return; - // } - // theStackedWidget->setCurrentIndex(3); - // } + else if(arg1 == "Digital Twin (MPM)" || arg1 == "MPM" || arg1 == "theMPM" || arg1 == "MPMDigitalTwin" || arg1 == "theMPMDigitalTwin" || arg1 == "MPM Digital Twin") { + MPM* theM = dynamic_cast(theMPM); + theCurrentEvent = theM->isInitialize() ? theMPM + : ( theM->initialize() ? theMPM : nullptr ); + if (!theCurrentEvent) { + qDebug() << "ERROR: Hydro-EventSelection failed while attempting to initialize the MPM Event, label: " << arg1; + return; + } + theStackedWidget->setCurrentIndex(3); + } // else if(arg1 == "Digital Twin (SPH)" || arg1 == "SPH" || arg1 == "theSPH" || arg1 == "SPHDigitalTwin" || arg1 == "theSPHDigitalTwin" || arg1 == "SPH Digital Twin") { // SPH* theM = dynamic_cast(theSPH); // theCurrentEvent = theM->isInitialize() ? theSPH @@ -272,6 +286,10 @@ void HydroEventSelection::eventSelectionChanged(const QString &arg1) // } // theStackedWidget->setCurrentIndex(4); // } + else if(arg1 == "Stochastic Wave Loading" || arg1 == "SimpleWaves") { + theCurrentEvent = theSimpleWaves; + theStackedWidget->setCurrentIndex(4); + } else { qDebug() << "ERROR .. HydroEventSelection selection .. type unknown: " << arg1; } @@ -341,12 +359,15 @@ bool HydroEventSelection::inputFromJSON(QJsonObject &jsonObject) { } else if ((type == QString("CoupledDigitalTwin")) || (type == QString("Digital Twin (OpenFOAM and OpenSees)")) || (type == QString("Digital Twin")) || (type == QString("CoupledDigitalTwin")) || (type == QString("theCoupledDigitalTwin"))){ index = 2; } - // else if ((type == QString("MPM")) || (type == QString("Material Point Method")) || (type == QString("Digital Twin (MPM)")) || (type == QString("MPMDigitalTwin")) || (type == QString("theMPM")) || (type == QString("MPM Digital Twin")) || (type == QString("MPMDigitalTwin")) || (type == QString("theMPMDigitalTwin"))){ - // index = 3; - // } + else if ((type == QString("MPM")) || (type == QString("Material Point Method")) || (type == QString("Digital Twin (MPM)")) || (type == QString("MPMDigitalTwin")) || (type == QString("theMPM")) || (type == QString("MPM Digital Twin")) || (type == QString("MPMDigitalTwin")) || (type == QString("theMPMDigitalTwin"))){ + index = 3; + } // // else if ((type == QString("SPH")) || (type == QString("Smoothed Particled Hydrodynamics")) || (type == QString("Digital Twin (SPH)")) || (type == QString("SPHDigitalTwin")) || (type == QString("theSPH")) || (type == QString("SPH Digital Twin")) || (type == QString("SPHDigitalTwin")) || (type == QString("theSPHDigitalTwin"))){ // index = 4; // } + else if ((type == QString("SimpleWaves")) || (type == QString("Stochastic Wave Loading"))) { + index = 4; + } else { qDebug() << "HydroEventSelection::inputFromJSON type unknown: " << type; @@ -446,18 +467,24 @@ bool HydroEventSelection::inputAppDataFromJSON(QJsonObject &jsonObject) theCurrentEvent = theCoupledDigitalTwin; index = 2; } - // else if (((type == "MPM") - // || (type == "Material Point Method")) || ((type == "General Event (MPM)") || (type == "Digital Twin (MPM)")) || (type == "MPMDigitalTwin") || (type == "theMPM")) { + else if (((type == "MPM") + || (type == "Material Point Method")) || ((type == "General Event (MPM)") || (type == "Digital Twin (MPM)")) || (type == "MPMDigitalTwin") || (type == "theMPM")) { - // theCurrentEvent = theMPM; - // index = 3; - // } + theCurrentEvent = theMPM; + index = 3; + } // else if (((type == "SPH") // || (type == "Smoothed Particle Hydrodynamics")) || ((type == "General Event (SPH)") || (type == "Digital Twin (SPH)")) || (type == "SPHDigitalTwin") || (type == "theSPH")) { // theCurrentEvent = theSPH; // index = 4; // } + else if ((type == "SimpleWaves") + || (type == "Stochastic Wave Loading")) { + + theCurrentEvent = theSimpleWaves; + index = 4; + } else { qDebug() << "HydroEventSelection::inputAppDataFromJSON type unknown: " << type; theCurrentEvent = theMPM; diff --git a/EVENTS/HydroEventSelection.h b/EVENTS/HydroEventSelection.h index f83d73f4..77acb742 100644 --- a/EVENTS/HydroEventSelection.h +++ b/EVENTS/HydroEventSelection.h @@ -110,6 +110,7 @@ public slots: SimCenterAppWidget *theCoupledDigitalTwin; SimCenterAppWidget *theMPM; SimCenterAppWidget *theSPH; + SimCenterAppWidget *theSimpleWaves; SimCenterAppWidget *theExistingEvents; RandomVariablesContainer *theRandomVariablesContainer; diff --git a/EVENTS/SimpleWaves/SimpleWaves.cpp b/EVENTS/SimpleWaves/SimpleWaves.cpp deleted file mode 100644 index 41310897..00000000 --- a/EVENTS/SimpleWaves/SimpleWaves.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* ***************************************************************************** -Copyright (c) 2016-2017, The Regents of the University of California (Regents). -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of the FreeBSD Project. - -REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS -PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, -UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - -*************************************************************************** */ - -// Written: JustinBonus - -#include "SimpleWaves.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// #include "slidingstackedwidget.h" - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -// #include -#include "QVector3D" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -// #include -// #include -// #include -// #include -// #include -// #include -// #include - -// Trying out -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include -// #include - -// #include - -SimpleWaves::SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget *parent) - : SimCenterAppWidget(parent), theRandomVariablesContainer(theRandomVariableIW) -{ - - - // Initialize member variables - dragCoefficient = new LineEditRV(randomVariables); - dragCoefficient->setText("2.1"); - - peakPeriod = new LineEditRV(randomVariables); - peakPeriod->setText("12.7"); - - significantWaveHeight = new LineEditRV(randomVariables); - significantWaveHeight->setText("8.1"); - - waterDepth = new LineEditRV(randomVariables); - waterDepth->setText("30.0"); - - recorderOriginX = new LineEditRV(randomVariables); - recorderOriginX->setText("0.0"); - - exposureCategory = new QComboBox(); - exposureCategory->addItem("B"); - exposureCategory->addItem("C"); - exposureCategory->addItem("D"); - - seed = new QSpinBox(); - seed->setMinimum(1); - seed->setMaximum(2147483647); - seed->setValue(500); - seed->setEnabled(false); - useSeed = new QRadioButton("Provide seed value"); - useSeed->setChecked(false); - - QFormLayout *parameters = new QFormLayout(); - - exposureCategory = new QComboBox(); - exposureCategory->addItem("B"); - exposureCategory->addItem("C"); - exposureCategory->addItem("D"); - - parameters->addRow(new QLabel(tr("Drag Coefficient")), dragCoefficient); - parameters->addRow(new QLabel(tr("Drag Area")), dragArea); - parameters->addRow(new QLabel(tr("Peak Period [s]")), peakPeriod); - parameters->addRow(new QLabel(tr("Significant Wave Height [m]")), significantWaveHeight); - parameters->addRow(new QLabel(tr("Water Depth [m]")), waterDepth); - parameters->addRow(new QLabel(tr("Recorder Horizontal Position [m]")), recorderOriginX); - parameters->addRow(new QLabel(tr("ASCE 7 Exposure Condition")), exposureCategory); -// parameters->addRow(new QLabel(tr("Gust Wind Speed (mph)")), gustWindSpeed); -// gustWindSpeed->setToolTip("3 sec gust speed at height of 10m (33ft)"); - // Add description label - modelDescription = - new QLabel(tr("This model provides wind speed time histories using a " - "power law for the wind profile based on the ASCE Exposure\n" - "Category and a discrete frequency function with FFT to " - "account for wind fluctuations (Wittig & Sinha, 1975)")); - //model_description_->setStyleSheet("QLabel { color : gray; }"); - - // Construct required layouts - QVBoxLayout* layout = new QVBoxLayout(); - QHBoxLayout* seedLayout = new QHBoxLayout(); - QHBoxLayout* parametersLayout = new QHBoxLayout(); - - // Add widgets to layouts and layouts to this - seedLayout->addWidget(useSeed); - seedLayout->addWidget(seed); - seedLayout->addStretch(); - parametersLayout->addLayout(parameters); - parametersLayout->addStretch(); - layout->addWidget(modelDescription); - layout->addLayout(parametersLayout); - layout->addLayout(seedLayout); - layout->addStretch(); - this->setLayout(layout); - - // Connect slots - connect(useSeed, &QRadioButton::toggled, this, - &WittigSinha::provideSeed); - -} - -SimpleWaves::~SimpleWaves() -{ - -} - - -void SimpleWaves::executeBackendScript() -{ - // - // Update JSON input file and then pass arguments to a python script. Runs script to prepare case directory. - // Python scripts hosted remotely by SimCenterBackendApplications/modules/createEVENT/* - // - - updateJSON(); - QString scriptName = "SimpleWaves.py"; // "setup_case.py"; - QString scriptPath = pyScriptsPath() + QDir::separator() + scriptName; - QString templatePath = "."; - QString jsonPath = caseDir() + QDir::separator() //+ "input"; - QString outputPath = caseDir() + QDir::separator() //+ "output"; - if (QFileInfo(scriptPath).exists()) - { - QString program = SimCenterPreferences::getInstance()->getPython(); - QStringList arguments; arguments << scriptPath << jsonPath << templatePath << outputPath; - QProcess *process = new QProcess(this); - process->start(program, arguments); - process->waitForFinished(-1); - process->close(); - } - else - { - qDebug() << "Cannot find the script path: " << scriptPath; - } - return; -} - -void SimpleWaves::onBrowseCaseDirectoryButtonClicked(void) -{ - // QString fileName = QFileDialog::getExistingDirectory(this, tr("Open Directory"), caseDir(), - // QFileDialog::ShowDirsOnly - // | QFileDialog::DontResolveSymlinks); - // QDir newCaseDir(fileName); - // if (!newCaseDir.exists()) - // { - // return; - // } - // caseDirectoryPathWidget->setText(fileName); - - // if (!isCaseConfigured()) - // { - // setupCase(); - // return; - // } - - // // Need to have JSON (SimpleWaves.json) in LocalWorkDir/SimpleWaves/constant/simCenter/input - // readCaseData(); - // caseDirectoryPathWidget->setText(fileName); - // return; -} - -void SimpleWaves::clear(void) -{ - - -} - -bool SimpleWaves::outputCitation(QJsonObject &jsonObject) -{ - QJsonObject citeClaymoreUW; - - citeClaymoreUW["citation"] = "Bonus, Justin (2023). “Evaluation of Fluid-Driven Debris Impacts in a High-Performance Multi-GPU Material Point Method.” PhD thesis, University of Washington, Seattle, WA."; - citeClaymoreUW["description"] = "The ClaymoreUW Multi-GPU Material Point Method software developed in this PhD thesis is the engineering refactor of the claymore SimpleWaves software. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It features higher computational precision, validated accuracy in multiple debris-fluid-structure interaction problems, new algorithms (ASFLIP, F-Bar antilocking), an expanded user-interface, and improved material behavior."; - jsonObject["welib"] = citeClaymoreUW; - return true; -} - -bool SimpleWaves::inputFromJSON(QJsonObject &jsonObject) -{ - this->clear(); - - QString newCaseDirectoryPath(jsonObject["caseDirectoryPath"].toString()); - - if (newCaseDirectoryPath.isEmpty()) { - qDebug() << "SimpleWaves::inputFromJSON: newCaseDirectoryPath is empty in JSON input."; - return false; - } - - QDir newCaseDir(newCaseDirectoryPath); - if (!newCaseDir.exists()) { - qDebug() << "SimpleWaves::inputFromJSON: newCaseDir does not exist in folder structure: " << newCaseDirectoryPath; - return false; - } - - if (newCaseDirectoryPath != caseDirectoryPathWidget->text()) { - caseDirectoryPathWidget->setText(newCaseDirectoryPath); - } - - caseDirectoryPathWidget->setText(jsonObject["caseDirectoryPath"].toString()); - - return true; -} - -bool SimpleWaves::outputToJSON(QJsonObject &jsonObject) -{ - - - - - bool result = true; - - jsonObject["type"] = "SimpleWaves"; - jsonObject["EventClassification"] = "Hydro"; - dragCoefficient->outputToJSON(jsonObject, QString("dragCoefficient")); - dragArea->outputToJSON(jsonObject, QString("dragArea")); - significantWaveHeight->outputToJSON(jsonObject, QString("significantWaveHeight")); - peakPeriod->outputToJSON(jsonObject, QString("peakPeriod")); - waterDepth->outputToJSON(jsonObject, QString("waterDepth")); - recorderOriginX->outputToJSON(jsonObject, QString("recorerOriginX")); - - jsonObject.insert("exposureCategory",exposureCategory->currentText()); - - if (useSeed->isChecked()) { - jsonObject.insert("seed", seed->value()); - } else { - jsonObject.insert("seed", "None"); - } - - return result; - - return true; -} - -bool SimpleWaves::outputAppDataToJSON(QJsonObject &jsonObject) { - - // - // Per API, need to add name of application to be called in Application - // and all data to be used in ApplicationData - // - - // jsonObject["EventClassification"] = "Hydro"; - // jsonObject["Application"] = "SimpleWaves"; - // QJsonObject dataObj; - // jsonObject["ApplicationData"] = dataObj; - - // jsonObject["programFile"] = "SimpleWaves"; // <- ClaymoreUW SimpleWaves executable filename on remote machine. Can be changed depending on compiled optimizations, versions, digital twin, etc. - // jsonObject["maxRunTime"] = "00:05:00"; // <- Maximum run time for the simulation, timeout if exceeded - return true; -} -bool SimpleWaves::inputAppDataFromJSON(QJsonObject &jsonObject) { - - Q_UNUSED(jsonObject); - return true; -} - - -bool SimpleWaves::copyFiles(QString &destDir) { - // - // Copy the files in the case directory to the destination directory - // This is the directory where the simulations will be run / staged - // Should pull together any files needed for the simulation, e.g. specified input files - // - - executeBackendScript(); - QString caseName = "SimpleWaves"; - QString destDirCase = destDir + QDir::separator() + caseName; - QDir destDirCaseDir(destDirCase); - if (!destDirCaseDir.exists()) - { - destDirCaseDir.mkpath("."); // Make the directory if it doesn't exist - } - bool result = this->copyPath(caseDir(), destDirCase, false); // False means don't copy the directory itself, just the contents - if (!result) - { - QString errorMessage; errorMessage = "SimpleWaves - failed to copy files in: " + caseDir() + " to: " + destDirCase; - emit sendFatalMessage(errorMessage); - qDebug() << errorMessage; - return false; - } - - return true; - } - - -bool SimpleWaves::removeOldFiles() -{ - // - // Remove extra files if they exist in case directory's "0" folder - // - - auto removeFile = [this](QString filePath) { - QFile file(caseDir() + QDir::separator() + "0" + QDir::separator() + filePath); - if (file.exists()) { - qDebug() << "Removing old file: " << filePath; - file.remove(); - } - }; - removeFile(caseDir() + QDir::separator() + "0" + QDir::separator() + "oldFile"); - return true; -} - -bool SimpleWaves::setupCase() -{ - cleanCase(); - QDir targetDir(caseDir()); - if (!targetDir.exists()) - { - targetDir.mkpath(caseDir()); - } - // targetDir.mkpath("0"); - // targetDir.mkpath("constant"); - // targetDir.mkpath("constant/geometry"); - // targetDir.mkpath("constant/simCenter"); - // targetDir.mkpath("constant/simCenter/output"); - // targetDir.mkpath("constant/simCenter/input"); - // targetDir.mkpath("constant/boundaryData"); - // targetDir.mkpath("constant/boundaryData/inlet"); - // targetDir.mkpath("system"); - - // Write setup files using the backend python script - executeBackendScript(); - return true; -} - - -bool SimpleWaves::isCaseConfigured() -{ - QDir zeroDir(caseDir() + QDir::separator() + "0"); - QDir constDir(caseDir() + QDir::separator() + "constant"); - QDir systemDir(caseDir() + QDir::separator() + "system"); - // QFile contrlDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "controlDict"); - // QFile blockDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "blockMeshDict"); - // QFile snappyDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "snappyHexMeshDict"); - - // //Better if we check other files too, for now these are enougg to run a mesh - // return zeroDir.exists() && constDir.exists() && systemDir.exists() && - // contrlDict.exists() && blockDict.exists() && snappyDict.exists(); - return zeroDir.exists() && constDir.exists() && systemDir.exists(); -} - -QString SimpleWaves::caseDir() -{ - return caseDirectoryPathWidget->text(); -} - -QString SimpleWaves::pyScriptsPath() -{ - // QString backendAppDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() - // + QString("applications") + QDir::separator() + QString("createEVENT") + QDir::separator() - // + QString("SimpleWaves"); - - QString backendAppDir = QString("./") + QDir::separator() - + QString("SimpleWaves"); - return backendAppDir; -} - -// Probably not needed for anything but OpenFOAM -QString SimpleWaves::templateDictDir() -{ - QString templateSubFolder = QString("templateOF10Dicts");// "templateSimpleWavesDicts"; - QString templateDictsDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() - + QString("applications") + QDir::separator() - + QString("createEVENT") + QDir::separator() - + QString("SimpleWaves") + QDir::separator() - + templateSubFolder; - return templateDictsDir; -} - -QString SimpleWaves::simulationType() -{ - return QString("SimpleWaves"); // Yet to support turbulence models in SimpleWaves, so its just "SimpleWaves" (i.e. DNS) -} - -SC_ResultsWidget* SimpleWaves::getResultsWidget(QWidget *parent) -{ - // theTabWidget.setCurrentIndex(theTabWidget.indexOf("Results")); - // Set theTabWidget to show the "Results" tab using its text - if (simpleWavesResults) - { - theTabWidget->setCurrentIndex(theTabWidget->count() - 1); - } - else - { - QWidget* resultsWidget = new QWidget(); - QVBoxLayout* resultsLayout = new QVBoxLayout(); - resultsWidget->setLayout(resultsLayout); - simpleWavesResults = new ResultsSimpleWaves(this); - - resultsLayout->addWidget(simpleWavesResults); - resultsLayout->addStretch(); - theTabWidget->addTab(resultsWidget, QIcon(QString(":/icons/flag-black.svg")), "Results"); - theTabWidget->setCurrentIndex(theTabWidget->count() - 1); - } - - statusMessage("HydroUQ EVENTS SimpleWaves - Get results widget for the EVT to allow us to post-process the downloaded results (or locally saved results) for visualization."); - return simpleWavesResults; -} - -void SimpleWaves::importMainDomainJsonFile(QJsonObject &jsonObject) -{ - // openFoamVersion->setCurrentText(jsonObject["OpenFoamVersion"].toString()); - // geometry->inputFromJSON(jsonObject); - // snappyHexMesh->inputFromJSON(jsonObject); - // windCharacteristics->inputFromJSON(jsonObject); - // boundaryConditions->inputFromJSON(jsonObject); - // turbulenceModeling->inputFromJSON(jsonObject); - // numericalSetup->inputFromJSON(jsonObject); -} - diff --git a/EVENTS/SimpleWaves/Ex1_WaveKinematics.py b/EVENTS/StochasticWaveModel/Ex1_WaveKinematics.py similarity index 100% rename from EVENTS/SimpleWaves/Ex1_WaveKinematics.py rename to EVENTS/StochasticWaveModel/Ex1_WaveKinematics.py diff --git a/EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py b/EVENTS/StochasticWaveModel/Ex2_Jonswap_spectrum.py similarity index 100% rename from EVENTS/SimpleWaves/Ex2_Jonswap_spectrum.py rename to EVENTS/StochasticWaveModel/Ex2_Jonswap_spectrum.py diff --git a/EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py b/EVENTS/StochasticWaveModel/Ex3_WaveTimeSeries.py similarity index 100% rename from EVENTS/SimpleWaves/Ex3_WaveTimeSeries.py rename to EVENTS/StochasticWaveModel/Ex3_WaveTimeSeries.py diff --git a/EVENTS/SimpleWaves/Ex4_WaveLoads.py b/EVENTS/StochasticWaveModel/Ex4_WaveLoads.py similarity index 99% rename from EVENTS/SimpleWaves/Ex4_WaveLoads.py rename to EVENTS/StochasticWaveModel/Ex4_WaveLoads.py index 6d35ecf8..5ae2189f 100644 --- a/EVENTS/SimpleWaves/Ex4_WaveLoads.py +++ b/EVENTS/StochasticWaveModel/Ex4_WaveLoads.py @@ -16,7 +16,7 @@ # --- Parameters g = 9.81 # gravity [m/s^2] h = 30. # water depth [m] -rho = 1025 # water density +rho = 1000 # water density D = 6 # monopile diameter [m] CD = 1 # given CM = 2 # diff --git a/EVENTS/StochasticWaveModel/SimpleWaves.cpp b/EVENTS/StochasticWaveModel/SimpleWaves.cpp new file mode 100644 index 00000000..ee6d983d --- /dev/null +++ b/EVENTS/StochasticWaveModel/SimpleWaves.cpp @@ -0,0 +1,655 @@ +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: JustinBonus + +#include "SimpleWaves.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include "slidingstackedwidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + + +// #include +#include "QVector3D" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// Trying out +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// #include + +SimpleWaves::SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget *parent) + : SimCenterAppWidget(parent), theRandomVariablesContainer(theRandomVariableIW) +{ + + + +// caseDirectoryPathWidget = new QLineEdit(); + + // Create label and add items to combo box for model selection + QLabel* selection_label = new QLabel(tr("Stochastic Loading Model")); + selection_label->setStyleSheet("font-weight: bold"); + modelSelection = new QComboBox(); + modelSelection->setObjectName("StochasticLoadingModel"); + modelSelection->addItem(tr("Ocean Wave Spectra")); +// stochasticModel = new WittigSinha(rvInputWidget, this); + + // Add widgets to layouts and layouts to this + QHBoxLayout* model_layout = new QHBoxLayout(); + + model_layout->addWidget(modelSelection); + model_layout->addStretch(); + + + +// // Initialize member variables + dragCoefficient = new LineEditRV(theRandomVariablesContainer); + dragCoefficient->setText("2.1"); + +// peakPeriod = new LineEditRV(theRandomVariablesContainer); +// peakPeriod->setText("12.7"); + +// significantWaveHeight = new LineEditRV(theRandomVariablesContainer); +// significantWaveHeight->setText("8.1"); + +// waterDepth = new LineEditRV(theRandomVariablesContainer); +// waterDepth->setText("30.0"); + +// recorderOriginX = new LineEditRV(theRandomVariablesContainer); +// recorderOriginX->setText("0.0"); + +// recorderCountZ = new SC_IntLineEdit("recorderCountZ",2); +// // recorderCountZ->setText("2"); + +// timeStep = new LineEditRV(theRandomVariablesContainer); +// timeStep->setText("0.1"); + +// timeDuration = new LineEditRV(theRandomVariablesContainer); +// timeDuration->setText("3600.0"); + +// exposureCategory = new QComboBox(); +// exposureCategory->addItem("JONSWAP"); + +// seed = new QSpinBox(); +// seed->setMinimum(1); +// seed->setMaximum(2147483647); +// seed->setValue(500); +// seed->setEnabled(false); +// useSeed = new QRadioButton("Provide seed value"); +// useSeed->setChecked(false); + + parametersLayout = new QHBoxLayout(); + QFormLayout *parameters = new QFormLayout(); + +// exposureCategory = new QComboBox(); +// exposureCategory->addItem("JONSWAP"); +// // exposureCategory->addItem("Pierson-Moskowitz"); + + parameters->addRow(new QLabel("Drag Coefficient"), dragCoefficient); +// parameters->addRow(new QLabel(tr("Drag Area")), dragArea); +// parameters->addRow(new QLabel(tr("Peak Period [s]")), peakPeriod); +// parameters->addRow(new QLabel(tr("Significant Wave Height [m]")), significantWaveHeight); +// parameters->addRow(new QLabel(tr("Water Depth [m]")), waterDepth); +// parameters->addRow(new QLabel(tr("Recorder Horizontal Position [m]")), recorderOriginX); +// parameters->addRow(new QLabel(tr("Wave Spectrum")), exposureCategory); +// parameters->addRow(new QLabel(tr("Time Step [s]")), timeStep); +// parameters->addRow(new QLabel(tr("Time Duration [s]")), timeDuration); + +// // parameters->addRow(new QLabel(tr("Gust Wind Speed (mph)")), gustWindSpeed); +// // gustWindSpeed->setToolTip("3 sec gust speed at height of 10m (33ft)"); +// // Add description label + modelDescription = + new QLabel(tr("This model provides wind speed time histories using a " + "power law for the wind profile based on the ASCE Exposure\n" + "Category and a discrete frequency function with FFT to " + "account for wind fluctuations (Wittig & Sinha, 1975)")); + //model_description_->setStyleSheet("QLabel { color : gray; }"); + +// // Construct required layouts +// // QVBoxLayout* mainWindowLayout = new QVBoxLayout(); +// QHBoxLayout* seedLayout = new QHBoxLayout(); +// // QHBoxLayout* parametersLayout = new QHBoxLayout(); + +// // Add widgets to layouts and layouts to this +// seedLayout->addWidget(useSeed); +// seedLayout->addWidget(seed); +// seedLayout->addStretch(); +QVBoxLayout* internalLayout = new QVBoxLayout(); +QHBoxLayout* internalParametersLayout = new QHBoxLayout(); + internalParametersLayout->addLayout(parameters); +// // parametersLayout->addWidget(stochasticModel); +// parametersLayout->addStretch(); + // Construct required layouts +internalLayout->addWidget(modelDescription); +internalLayout->addLayout(internalParametersLayout); +// internalLayout->addLayout(seedLayout); +internalLayout->addStretch(); + +QWidget* internalWidget = new QWidget(); +internalWidget->setLayout(internalLayout); + +// QScrollArea* scrollArea = new QScrollArea(); +// scrollArea->setWidget(internalWidget); +// scrollArea->setWidgetResizable(true); + + + +parametersLayout->addWidget(internalWidget); +parametersLayout->addStretch(); + + mainWindowLayout = new QHBoxLayout(); + mainWindowLayout->addWidget(selection_label); + mainWindowLayout->addLayout(model_layout); + mainWindowLayout->addLayout(parametersLayout); +// mainWindowLayout->addLayout(seedLayout); + mainWindowLayout->addStretch(); + this->setLayout(mainWindowLayout); + +// // Connect slots +// connect(useSeed, &QRadioButton::toggled, this, +// &SimpleWaves::provideSeed); + +} + +SimpleWaves::~SimpleWaves() +{ + +} + + +void SimpleWaves::executeBackendScript() +{ + // + // Update JSON input file and then pass arguments to a python script. Runs script to prepare case directory. + // Python scripts hosted remotely by SimCenterBackendApplications/modules/createEVENT/* + // + + // updateJSON(); + // QString scriptName = "SimpleWaves.py"; // "setup_case.py"; + QString scriptName = "Ex4_WaveLoads.py"; // "setup_case.py"; + QString scriptPath = pyScriptsPath() + QDir::separator() + scriptName; + QString templatePath = "."; + + + + QString jsonPath = SimCenterPreferences::getInstance()->getLocalWorkDir() + QDir::separator(); + QString outputPath = SimCenterPreferences::getInstance()->getLocalWorkDir() + QDir::separator(); //+ "output"; + if (QFileInfo(scriptPath).exists()) + { + QString program = SimCenterPreferences::getInstance()->getPython(); + QStringList arguments; arguments << scriptPath; //<< jsonPath << templatePath << outputPath; + QProcess *process = new QProcess(this); + process->start(program, arguments); + process->waitForFinished(-1); + process->close(); + } + else + { + qDebug() << "Cannot find the script path: " << scriptPath; + } + return; +} + +void SimpleWaves::onBrowseCaseDirectoryButtonClicked(void) +{ + // QString fileName = QFileDialog::getExistingDirectory(this, tr("Open Directory"), caseDir(), + // QFileDialog::ShowDirsOnly + // | QFileDialog::DontResolveSymlinks); + // QDir newCaseDir(fileName); + // if (!newCaseDir.exists()) + // { + // return; + // } + // caseDirectoryPathWidget->setText(fileName); + + // if (!isCaseConfigured()) + // { + // setupCase(); + // return; + // } + + // // Need to have JSON (SimpleWaves.json) in LocalWorkDir/SimpleWaves/constant/simCenter/input + // readCaseData(); + // caseDirectoryPathWidget->setText(fileName); + // return; +} + +void SimpleWaves::clear(void) +{ + // // Clear all widgets + // dragCoefficient->clear(); + // dragArea->clear(); + // significantWaveHeight->clear(); + // peakPeriod->clear(); + // waterDepth->clear(); + // recorderOriginX->clear(); + // recorderCountZ->clear(); + // timeStep->clear(); + // timeDuration->clear(); + // seed->clear(); + // useSeed->setChecked(false); + // exposureCategory->setCurrentIndex(0); + // return; + +} + +bool SimpleWaves::outputCitation(QJsonObject &jsonObject) +{ + QJsonObject citeClaymoreUW; + + citeClaymoreUW["citation"] = "Bonus, Justin (2023). “Evaluation of Fluid-Driven Debris Impacts in a High-Performance Multi-GPU Material Point Method.” PhD thesis, University of Washington, Seattle, WA."; + citeClaymoreUW["description"] = "The ClaymoreUW Multi-GPU Material Point Method software developed in this PhD thesis is the engineering refactor of the claymore SimpleWaves software. It is a highly optimized C++/CUDA code for explicit MLS-SimpleWaves simulations on multiple NVIDIA GPUs. It features higher computational precision, validated accuracy in multiple debris-fluid-structure interaction problems, new algorithms (ASFLIP, F-Bar antilocking), an expanded user-interface, and improved material behavior."; + jsonObject["welib"] = citeClaymoreUW; + return true; +} + +bool SimpleWaves::inputFromJSON(QJsonObject &jsonObject) +{ + this->clear(); + + + if (jsonObject.contains("exposureCategory")) { + + QJsonValue theValue = jsonObject["exposureCategory"]; + if (theValue.isString()) { + QString exposure = theValue.toString(); + exposureCategory->setCurrentText(exposure); + } + } + + if (jsonObject.contains("seed")) { + if (jsonObject["seed"].isString()) { + useSeed->setChecked(false); + } else { + useSeed->setChecked(true); + seed->setValue(jsonObject["seed"].toInt()); + } + } else { + useSeed->setChecked(false); + } + + dragCoefficient->inputFromJSON(jsonObject, QString("dragCoefficient")); + dragArea->inputFromJSON(jsonObject, QString("dragArea")); + significantWaveHeight->inputFromJSON(jsonObject, QString("significantWaveHeight")); + peakPeriod->inputFromJSON(jsonObject, QString("peakPeriod")); + waterDepth->inputFromJSON(jsonObject, QString("waterDepth")); + recorderOriginX->inputFromJSON(jsonObject, QString("recorderOriginX")); + recorderCountZ->inputFromJSON(jsonObject); + timeStep->inputFromJSON(jsonObject, QString("timeStep")); + timeDuration->inputFromJSON(jsonObject, QString("timeDuration")); + + // dragCoefficient->inputFromJSON(jsonObject["dragCoefficient"].toObject()); + // dragArea->inputFromJSON(jsonObject["dragArea"].toObject()); + // significantWaveHeight->inputFromJSON(jsonObject["significantWaveHeight"].toObject()); + // peakPeriod->inputFromJSON(jsonObject["peakPeriod"].toObject()); + // waterDepth->inputFromJSON(jsonObject["waterDepth"].toObject()); + // recorderOriginX->inputFromJSON(jsonObject["recorderOriginX"].toObject()); + // recorderCountZ->inputFromJSON(jsonObject["recorderCountZ"].toObject()); + // timeStep->inputFromJSON(jsonObject["timeStep"].toObject()); + // timeDuration->inputFromJSON(jsonObject["timeDuration"].toObject()); + + return true; +} + +bool SimpleWaves::outputToJSON(QJsonObject &jsonObject) +{ + + + + + bool result = true; + + jsonObject["type"] = "SimpleWaves"; + jsonObject["EventClassification"] = "Hydro"; + dragCoefficient->outputToJSON(jsonObject, QString("dragCoefficient")); + dragArea->outputToJSON(jsonObject, QString("dragArea")); + significantWaveHeight->outputToJSON(jsonObject, QString("significantWaveHeight")); + peakPeriod->outputToJSON(jsonObject, QString("peakPeriod")); + waterDepth->outputToJSON(jsonObject, QString("waterDepth")); + recorderOriginX->outputToJSON(jsonObject, QString("recorderOriginX")); + recorderCountZ->outputToJSON(jsonObject); + timeStep->outputToJSON(jsonObject, QString("timeStep")); + timeDuration->outputToJSON(jsonObject, QString("timeDuration")); + + jsonObject.insert("exposureCategory",exposureCategory->currentText()); + + if (useSeed->isChecked()) { + jsonObject.insert("seed", seed->value()); + } else { + jsonObject.insert("seed", "None"); + } + + return result; + + return true; +} + +bool SimpleWaves::outputAppDataToJSON(QJsonObject &jsonObject) { + + // + // Per API, need to add name of application to be called in Application + // and all data to be used in ApplicationData + // + + // jsonObject["EventClassification"] = "Hydro"; + // jsonObject["Application"] = "SimpleWaves"; + // QJsonObject dataObj; + // jsonObject["ApplicationData"] = dataObj; + + // jsonObject["programFile"] = "SimpleWaves"; // <- ClaymoreUW SimpleWaves executable filename on remote machine. Can be changed depending on compiled optimizations, versions, digital twin, etc. + // jsonObject["maxRunTime"] = "00:05:00"; // <- Maximum run time for the simulation, timeout if exceeded + return true; +} + +bool SimpleWaves::inputAppDataFromJSON(QJsonObject &jsonObject) { + + Q_UNUSED(jsonObject); + return true; +} + + +bool SimpleWaves::copyFiles(QString &destDir) { + // + // Copy the files in the case directory to the destination directory + // This is the directory where the simulations will be run / staged + // Should pull together any files needed for the simulation, e.g. specified input files + // + + // executeBackendScript(); + // QString caseName = "SimpleWaves"; + // QString destDirCase = destDir + QDir::separator() + caseName; + // QDir destDirCaseDir(destDirCase); + // if (!destDirCaseDir.exists()) + // { + // destDirCaseDir.mkpath("."); // Make the directory if it doesn't exist + // } + // bool result = this->copyPath(caseDir(), destDirCase, false); // False means don't copy the directory itself, just the contents + // if (!result) + // { + // QString errorMessage; errorMessage = "SimpleWaves - failed to copy files in: " + caseDir() + " to: " + destDirCase; + // emit sendFatalMessage(errorMessage); + // qDebug() << errorMessage; + // return false; + // } + + return true; + } + + +// bool SimpleWaves::removeOldFiles() +// { +// // +// // Remove extra files if they exist in case directory's "0" folder +// // + +// auto removeFile = [this](QString filePath) { +// QFile file(caseDir() + QDir::separator() + "0" + QDir::separator() + filePath); +// if (file.exists()) { +// qDebug() << "Removing old file: " << filePath; +// file.remove(); +// } +// }; +// removeFile(caseDir() + QDir::separator() + "0" + QDir::separator() + "oldFile"); +// return true; +// } + +// bool SimpleWaves::setupCase() +// { +// // cleanCase(); +// QDir targetDir(caseDir()); +// if (!targetDir.exists()) +// { +// targetDir.mkpath(caseDir()); +// } +// // targetDir.mkpath("0"); +// // targetDir.mkpath("constant"); +// // targetDir.mkpath("constant/geometry"); +// // targetDir.mkpath("constant/simCenter"); +// // targetDir.mkpath("constant/simCenter/output"); +// // targetDir.mkpath("constant/simCenter/input"); +// // targetDir.mkpath("constant/boundaryData"); +// // targetDir.mkpath("constant/boundaryData/inlet"); +// // targetDir.mkpath("system"); + +// // Write setup files using the backend python script +// executeBackendScript(); +// return true; +// } + + +// bool SimpleWaves::isCaseConfigured() +// { +// QDir zeroDir(caseDir() + QDir::separator() + "0"); +// QDir constDir(caseDir() + QDir::separator() + "constant"); +// QDir systemDir(caseDir() + QDir::separator() + "system"); +// // QFile contrlDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "controlDict"); +// // QFile blockDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "blockMeshDict"); +// // QFile snappyDict(caseDir() + QDir::separator() + "system" + QDir::separator() + "snappyHexMeshDict"); + +// // //Better if we check other files too, for now these are enougg to run a mesh +// // return zeroDir.exists() && constDir.exists() && systemDir.exists() && +// // contrlDict.exists() && blockDict.exists() && snappyDict.exists(); +// return zeroDir.exists() && constDir.exists() && systemDir.exists(); +// } + +// QString SimpleWaves::caseDir() +// { +// caseDirectoryPathWidget->setText(SimCenterPreferences::getInstance()->getLocalWorkDir()); + +// return caseDirectoryPathWidget->text(); +// } + +QString SimpleWaves::pyScriptsPath() +{ + // QString backendAppDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() + // + QString("applications") + QDir::separator() + QString("createEVENT") + QDir::separator() + // + QString("SimpleWaves"); + + QString backendAppDir = QString("./") + QDir::separator(); + return backendAppDir; +} + +// // Probably not needed for anything but OpenFOAM +// QString SimpleWaves::templateDictDir() +// { +// QString templateSubFolder = QString("templateOF10Dicts");// "templateSimpleWavesDicts"; +// QString templateDictsDir = SimCenterPreferences::getInstance()->getAppDir() + QDir::separator() +// + QString("applications") + QDir::separator() +// + QString("createEVENT") + QDir::separator() +// + QString("SimpleWaves") + QDir::separator() +// + templateSubFolder; +// return templateDictsDir; +// } + +// QString SimpleWaves::simulationType() +// { +// return QString("SimpleWaves"); // Yet to support turbulence models in SimpleWaves, so its just "SimpleWaves" (i.e. DNS) +// } + +// SC_ResultsWidget* SimpleWaves::getResultsWidget(QWidget *parent) +// { +// // theTabWidget.setCurrentIndex(theTabWidget.indexOf("Results")); +// // Set theTabWidget to show the "Results" tab using its text +// if (simpleWavesResults) +// { +// theTabWidget->setCurrentIndex(theTabWidget->count() - 1); +// } +// else +// { +// QWidget* resultsWidget = new QWidget(); +// QVBoxLayout* resultsLayout = new QVBoxLayout(); +// resultsWidget->setLayout(resultsLayout); +// simpleWavesResults = new ResultsSimpleWaves(this); + +// resultsLayout->addWidget(simpleWavesResults); +// resultsLayout->addStretch(); +// theTabWidget->addTab(resultsWidget, QIcon(QString(":/icons/flag-black.svg")), "Results"); +// theTabWidget->setCurrentIndex(theTabWidget->count() - 1); +// } + +// statusMessage("HydroUQ EVENTS SimpleWaves - Get results widget for the EVT to allow us to post-process the downloaded results (or locally saved results) for visualization."); +// return simpleWavesResults; +// } + + + +void SimpleWaves::provideSeed(const bool& checked) { + if (checked) { + seed->setEnabled(true); + } else { + seed->setEnabled(false); + seed->setValue(500); + } +} \ No newline at end of file diff --git a/EVENTS/SimpleWaves/SimpleWaves.h b/EVENTS/StochasticWaveModel/SimpleWaves.h similarity index 60% rename from EVENTS/SimpleWaves/SimpleWaves.h rename to EVENTS/StochasticWaveModel/SimpleWaves.h index c88ad42a..9bda4340 100644 --- a/EVENTS/SimpleWaves/SimpleWaves.h +++ b/EVENTS/StochasticWaveModel/SimpleWaves.h @@ -43,19 +43,24 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include // #include +#include +#include +#include +#include -#include +#include +#include +#include + + +// #include // Forward declaration class InputWidgetParameters; class RandomVariablesContainer; class LineEditRV; - -// class SettingsSimpleWaves; -// class BodiesSimpleWaves; -// class BoundariesSimpleWaves; -// class SensorsSimpleWaves; -// class OutputsSimpleWaves; -// class ResultsSimpleWaves; +class QJsonObject; +class QString; +class QWidget; class SC_DoubleLineEdit; class SC_IntLineEdit; @@ -74,6 +79,10 @@ class QPushButton; class QCheckBox; class QFormLayout; class QLabel; +class QRadioButton; +class QStackedWidget; + + class SimpleWaves : public SimCenterAppWidget { Q_OBJECT @@ -81,7 +90,7 @@ class SimpleWaves : public SimCenterAppWidget public: explicit SimpleWaves(RandomVariablesContainer *theRandomVariableIW, QWidget *parent = 0); // SimpleWaves( QWidget *parent = 0); - ~SimpleWaves(); + ~SimpleWaves() ; // friend class ResultsSimpleWaves; // Allow ResultsSimpleWaves to access private members. TODO: use a better vis architecture @@ -95,24 +104,21 @@ class SimpleWaves : public SimCenterAppWidget // bool initialize(); // bool isInitialize(); - bool setupCase(); - bool cleanCase(); - bool removeOldFiles(); - bool isCaseConfigured(); - void readCaseData(); +// bool setupCase(); +// bool cleanCase(); +// bool removeOldFiles(); +// bool isCaseConfigured(); +// void readCaseData(); // void importMainDomainJsonFile(QJsonObject &rvObject); // QVector> readTxtData(QString fileName); void executeBackendScript(); - void updateJSON(); - QString caseDir(); - QString templateDictDir(); +// void updateJSON(); +// QString caseDir(); QString pyScriptsPath(); - QString simulationType(); - // QString foamDictsPath(); // For OpenFOAM from WE-UQ, not SimpleWaves - SC_ResultsWidget* getResultsWidget(QWidget *parent) override; // For vis of output data results +// SC_ResultsWidget* getResultsWidget(QWidget *parent) override; // For vis of output data results signals: @@ -120,30 +126,55 @@ public slots: void clear(void) override; void onBrowseCaseDirectoryButtonClicked(void); + /** + * Update ability to provide seed based on changed status of radio button + * @param[in] checked Current status of radio button for providing seed + */ + void provideSeed(const bool& checked); + private: QHBoxLayout *mainWindowLayout; - QGridLayout *mainLayout; -// SettingsSimpleWaves *mpmSettings; -// BodiesSimpleWaves *mpmBodies; -// BoundariesSimpleWaves *mpmBoundaries; -// SensorsSimpleWaves *mpmSensors; -// OutputsSimpleWaves *mpmOutputs; -// ResultsSimpleWaves *mpmResults; +// QGridLayout *mainLayout; +// +// RandomVariablesContainer* rvInputWidget; /**< Widget for inputting random + // variables */ + QHBoxLayout * parametersLayout; /**< Layout for stochastic model widget */ + QComboBox* modelSelection; /**< Selection of ground motion model inputs */ RandomVariablesContainer *theRandomVariablesContainer; - QStringList varNamesAndValues; - - QString workingDirPath; - QLineEdit *caseDirectoryPathWidget; - QGroupBox *caseDirectoryGroup; - QGridLayout *caseDirectoryLayout; - QTabWidget *theTabWidget; - // QVBoxLayout *visWindowLayout; - // QGroupBox *visWindowGroup; - // QVBoxLayout *inputWindowLayout; - // QGroupBox *inputWindowGroup; -// bool caseInitialized = false; - QWebEngineView* m_pWebView; +// QStringList varNamesAndValues; + +// QString workingDirPath; +// QLineEdit *caseDirectoryPathWidget; + + + +// QGroupBox *caseDirectoryGroup; +// QGridLayout *caseDirectoryLayout; +// QTabWidget *theTabWidget; + + + QLabel *modelDescription; /**< Brief description of model indicating relevant + paper where more information can be found describing + model in greater detail */ + + QComboBox *exposureCategory; /**< type of wave spectrum */ + LineEditRV *dragCoefficient; /**< drag Coefficient */ + LineEditRV *dragArea; /**< drag Area */ + LineEditRV *significantWaveHeight; /**< significant wave height (ft) */ + LineEditRV *peakPeriod; /**< peak period (s) */ + LineEditRV *waterDepth; /**< water depth (ft) */ + LineEditRV *recorderOriginX; /**< x-coordinate of recorder origin */ + SC_IntLineEdit *recorderCountZ; /**< number of recorders in z-direction */ + LineEditRV *timeStep; /**< time step (s) */ + LineEditRV *timeDuration; /**< time duration (s) */ + + + + QSpinBox *seed; /**< Value to use as seed for motion generation */ + QRadioButton *useSeed; /**< Radio button to indicate whether specific seed + value should be used */ + }; #endif // SIMPLE_WAVES_H diff --git a/EVENTS/StochasticWaveModel/include/Jonswap.h b/EVENTS/StochasticWaveModel/include/Jonswap.h new file mode 100644 index 00000000..8a710732 --- /dev/null +++ b/EVENTS/StochasticWaveModel/include/Jonswap.h @@ -0,0 +1,137 @@ +#ifndef _KWON_KAREEM_2006_H +#define _KWON_KAREEM_2006_H + +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: mhgardner + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Forward declarations +class LineEditRV; +class QFormLayout; +class QJsonObject; +class QLabel; +class QLineEdit; +class QRadioButton; +class QSpinBox; +class QString; +class QWidget; +class QComboBox; +class RandomVariablesContainer; + +/** + * Widget for inputting parameters for stochastic earthquake time history + * generation model + */ +class Jonswap : public SimCenterAppWidget { + Q_OBJECT + public: + /** + * @constructor Construct new stochastic model input widget + * @param[in, out] random_variables Widget to store random variables to + * @param[in, out] parent Pointer to parent widget. Defaults to nullptr. + */ + explicit Jonswap(RandomVariablesContainer* random_variables, + QWidget* parent = nullptr); + + /** + * @destructor Virtual desctructor for stochastic model input widget + */ + virtual ~Jonswap() {}; + + /** + * Instantiate stochastic motion input widget from input JSON object + * @param[in] jsonObject JSON object containing input information + * @return Returns true if successful, false otherwise + */ + bool inputFromJSON(QJsonObject& jsonObject); + + /** + * Write all current class data to JSON required to reconstruct class + * @param[in, out] jsonObject JSON object to write output to + * @return Returns true if successful, false otherwise + */ + bool outputToJSON(QJsonObject& jsonObject); + + bool inputAppDataFromJSON(QJsonObject& jsonObject); + + /** + * Write application name to object and add a black ApplicationData + * @param[in, out] jsonObject JSON object to write output to + * @return Returns true if successful, false otherwise + */ + + bool outputAppDataToJSON(QJsonObject& jsonObject); + + /** + * Read application specific data + * @param[in, out] jsonObject JSON object to write output to + * @return Returns true if successful, false otherwise + */ + + public slots: + /** + * Update ability to provide seed based on changed status of radio button + * @param[in] checked Current status of radio button for providing seed + */ + void provideSeed(const bool& checked); + + protected: + QLabel *modelDescription; /**< Brief description of model indicating relevant + paper where more information can be found describing + model in greater detail */ + + QComboBox *exposureCategory; /**< ASCE 7 Exposure condition */ + LineEditRV *dragCoefficient; /**< drag Coefficient */ + LineEditRV *gustWindSpeed; /**< gust wnind speed (mph) */ + QSpinBox *seed; /**< Value to use as seed for motion generation */ + QRadioButton *useSeed; /**< Radio button to indicate whether specific seed + value should be used */ +}; + +#endif // _KWON_KAREEM_2006_MODEL_H \ No newline at end of file diff --git a/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h b/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h new file mode 100644 index 00000000..91131d0a --- /dev/null +++ b/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h @@ -0,0 +1,129 @@ +#ifndef _STOCHASTIC_WIND_INPUT_H +#define _STOCHASTIC_WIND_INPUT_H + +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: mhgardner + +#include +#include +#include +#include +#include +#include + +// Forward declarations +class QComboBox; +class QJsonObject; +class QString; +class QWidget; +class RandomVariableInputWidget; + +/** + * Widget for inputting parameters for stochastic earthquake time history + * generation + */ +class StochasticWaveInput : public SimCenterAppWidget { + Q_OBJECT + public: + /** + * @constructor Construct new stochastic motion input widget + * @param[in, out] random_variables Widget to store random variables to + * @param[in, out] parent Pointer to parent widget. Defaults to nullptr. + */ + explicit StochasticWaveInput(RandomVariablesContainer* random_variables, + QWidget* parent = nullptr); + + /** + * @destructor Virtual desctructor for stochastic input widget + */ + virtual ~StochasticWaveInput(); + + /** + * Instantiate stochastice motion input widger from input JSON object + * @param[in] rvObject JSON object containing input information + * @return Returns true if successful, false otherwise + */ + bool inputFromJSON(QJsonObject& rvObject); + + /** + * Write all current class data to JSON required to reconstruct class + * @param[in, out] rvObject JSON object to write output to + * @return Returns true if successful, false otherwise + */ + bool outputToJSON(QJsonObject& rvObject); + + /** + * Read application-specific data from JSON object + * @param[in] rvObject JSON object to read application data from + * @return Returns true if successful, false otherwise + */ + bool inputAppDataFromJSON(QJsonObject& rvObject); + + /** + * Write application-specific data to JSON object + * @param[in, out] rvObject JSON object to write application data to + * @return Returns true if successful, false otherwise + */ + bool outputAppDataToJSON(QJsonObject& rvObject); + + signals: + void sendErrorMessage(QString message); + + public slots: + /** + * Emit error message displaing input message + * @param[in] message String containg error message to emit + */ + void errorMessage(QString message); + + /** + * Emit change in model selection + * @param[in] model String name currently selected model + */ + void modelSelectionChanged(const QString& model); + + private: + RandomVariablesContainer* rvInputWidget; /**< Widget for inputting random + variables */ + QHBoxLayout * parametersLayout; /**< Layout for stochastic model widget */ + QComboBox* modelSelection; /**< Selection of ground motion model inputs */ + SimCenterAppWidget* stochasticModel; /**< Widget for inputting currently + selected model parameters */ +}; + +#endif // _STOCHASTIC_WIND_MODEL_H \ No newline at end of file diff --git a/EVENTS/StochasticWaveModel/src/Jonswap.cpp b/EVENTS/StochasticWaveModel/src/Jonswap.cpp new file mode 100644 index 00000000..3b90bbcd --- /dev/null +++ b/EVENTS/StochasticWaveModel/src/Jonswap.cpp @@ -0,0 +1,188 @@ +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: mhgardner +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +Jonswap::Jonswap(RandomVariablesContainer* randomVariables, + QWidget* parent) +: SimCenterAppWidget(parent) +{ + + // Initialize member variables + dragCoefficient = new LineEditRV(randomVariables); + dragCoefficient->setText("1.5"); + + gustWindSpeed = new LineEditRV(randomVariables); + gustWindSpeed->setText("50.0"); + + exposureCategory = new QComboBox(); + exposureCategory->addItem("B"); + exposureCategory->addItem("C"); + exposureCategory->addItem("D"); + + seed = new QSpinBox(); + seed->setMinimum(1); + seed->setMaximum(2147483647); + seed->setValue(500); + seed->setEnabled(false); + useSeed = new QRadioButton("Provide seed value"); + useSeed->setChecked(false); + + QFormLayout *parameters = new QFormLayout(); + + exposureCategory = new QComboBox(); + exposureCategory->addItem("B"); + exposureCategory->addItem("C"); + exposureCategory->addItem("D"); + + parameters->addRow(new QLabel(tr("Drag Coefficient")), dragCoefficient); + parameters->addRow(new QLabel(tr("ASCE 7 Exposure Condition")), exposureCategory); + parameters->addRow(new QLabel(tr("Gust Wind Speed (mph)")), gustWindSpeed); + gustWindSpeed->setToolTip("3 sec gust speed at height of 10m (33ft)"); + // Add description label + modelDescription = + new QLabel(tr("This model provides wave spectra using a " + "JONSWAP empirical distribution.")); + //model_description_->setStyleSheet("QLabel { color : gray; }"); + + // Construct required layouts + QVBoxLayout* layout = new QVBoxLayout(); + QHBoxLayout* seedLayout = new QHBoxLayout(); + QHBoxLayout* parametersLayout = new QHBoxLayout(); + + // Add widgets to layouts and layouts to this + seedLayout->addWidget(useSeed); + seedLayout->addWidget(seed); + seedLayout->addStretch(); + parametersLayout->addLayout(parameters); + parametersLayout->addStretch(); + layout->addWidget(modelDescription); + layout->addLayout(parametersLayout); + layout->addLayout(seedLayout); + layout->addStretch(); + this->setLayout(layout); + + // Connect slots + connect(useSeed, &QRadioButton::toggled, this, + &Jonswap::provideSeed); +} + + +bool Jonswap::outputAppDataToJSON(QJsonObject& jsonObject) { + bool result = true; + + jsonObject["Application"] = "StochasticWaveJonswap"; + jsonObject["EventClassification"] = "Hydro"; + + // squirel in the application data selection text + QJsonObject appData; + jsonObject["ApplicationData"] = appData; + + return result; +} + +bool Jonswap::inputAppDataFromJSON(QJsonObject& jsonObject) { + Q_UNUSED(jsonObject); + return true; +} + +bool Jonswap::outputToJSON(QJsonObject& jsonObject) { + bool result = true; + + jsonObject["type"] = "StochasticWaveJonswap"; + jsonObject["EventClassification"] = "Hydro"; + dragCoefficient->outputToJSON(jsonObject, QString("dragCoefficient")); + gustWindSpeed->outputToJSON(jsonObject, QString("gustSpeed")); + jsonObject.insert("exposureCategory",exposureCategory->currentText()); + + if (useSeed->isChecked()) { + jsonObject.insert("seed", seed->value()); + } else { + jsonObject.insert("seed", "None"); + } + + return result; +} + +bool Jonswap::inputFromJSON(QJsonObject& jsonObject) { + bool result = true; + + dragCoefficient->inputFromJSON(jsonObject, QString("dragCoefficient")); + gustWindSpeed->inputFromJSON(jsonObject, QString("gustSpeed")); + + if (jsonObject.contains("exposureCategory")) { + + QJsonValue theValue = jsonObject["exposureCategory"]; + if (theValue.isString()) { + QString exposure = theValue.toString(); + exposureCategory->setCurrentText(exposure); + } + } + + if (jsonObject.value("seed").isString()) { + useSeed->setChecked(false); + } else { + useSeed->setChecked(true); + seed->setValue(jsonObject.value("seed").toInt()); + } + + return result; +} + +void Jonswap::provideSeed(const bool& checked) { + if (checked) { + seed->setEnabled(true); + } else { + seed->setEnabled(false); + seed->setValue(500); + } +} \ No newline at end of file diff --git a/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp b/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp new file mode 100644 index 00000000..0456f84b --- /dev/null +++ b/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp @@ -0,0 +1,168 @@ +/* ***************************************************************************** +Copyright (c) 2016-2017, The Regents of the University of California (Regents). +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. + +REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS +PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*************************************************************************** */ + +// Written: mhgardner + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +StochasticWaveInput::StochasticWaveInput( + RandomVariablesContainer* random_variables, QWidget* parent) + : SimCenterAppWidget(parent), + rvInputWidget(random_variables) { + // Construct required layouts + QVBoxLayout* layout = new QVBoxLayout(); + QHBoxLayout* model_layout = new QHBoxLayout(); + parametersLayout = new QHBoxLayout(); + + // Create label and add items to combo box for model selection + QLabel* selection_label = new QLabel(tr("Stochastic Loading Model")); + //selection_label->setStyleSheet("font-weight: bold"); + modelSelection = new QComboBox(); + modelSelection->setObjectName("StochasticLoadingModel"); + modelSelection->addItem(tr("JONSWAP")); + stochasticModel = new Jonswap(rvInputWidget, this); + + // Add widgets to layouts and layouts to this + + model_layout->addWidget(modelSelection); + model_layout->addStretch(); + parametersLayout->addWidget(stochasticModel); + parametersLayout->addStretch(); + layout->addWidget(selection_label); + layout->addLayout(model_layout); + layout->addLayout(parametersLayout); + layout->addStretch(); + this->setLayout(layout); + + // Connect model selection slot + connect(modelSelection, SIGNAL(currentTextChanged()), this, SLOT(modelSelectionChanged)); +} + + +StochasticWaveInput::~StochasticWaveInput() { + +} + +bool StochasticWaveInput::outputToJSON(QJsonObject& jsonObject) { + bool result = false; + if (stochasticModel != NULL) + return stochasticModel->outputToJSON(jsonObject); + else { + qDebug() << "StocashicWaveInput::outputToJSON - NULL model"; + } + + return result; +} + +bool StochasticWaveInput::inputFromJSON(QJsonObject& jsonObject) { + + bool result = false; + if (stochasticModel != NULL) + return stochasticModel->inputFromJSON(jsonObject); + else { + qDebug() << "StocashicWaveInput::outputToJSON - NULL model"; + } + + return result; +} + +bool StochasticWaveInput::outputAppDataToJSON(QJsonObject& jsonObject) { + + bool result = false; + if (stochasticModel != NULL) + return stochasticModel->outputAppDataToJSON(jsonObject); + else { + qDebug() << "StocashicWaveInput::outputToJSON - NULL model"; + } + return result; +} + + +bool StochasticWaveInput::inputAppDataFromJSON(QJsonObject& jsonObject) { + + QString appName; + appName = jsonObject.value("Application").toString(); + if (appName == "StochasticWaveJonswap") { + + this->modelSelectionChanged(QString("JONSWAP")); + stochasticModel->inputAppDataFromJSON(jsonObject); // no check for NULL as cannot be if i can write code! + } + + else { + QString message = QString("StocashicWaveInput::inputAppDataFromJSON - unknown application string: ") + appName; + // qDebug() << message; + emit errorMessage(message); + } + + return true; +} + +void StochasticWaveInput::modelSelectionChanged(const QString& model) { + + // Switch the model description and form layout based on model selection + SimCenterAppWidget *nextModel = NULL; + if (model == "JONSWAP") { + nextModel = new Jonswap(rvInputWidget, this); + } else { + qDebug() << "ERROR: StochasticWaveInput::modelSelectionChanged: Unknown selection: " << model << "\n"; + } + + if (nextModel != NULL) { + if (stochasticModel != NULL) { + parametersLayout->replaceWidget(stochasticModel, nextModel); + delete stochasticModel; + stochasticModel = nextModel; + } + } +} + +void StochasticWaveInput::errorMessage(QString message) { + emit sendErrorMessage(message); +} \ No newline at end of file diff --git a/HydroEVENTS.pri b/HydroEVENTS.pri index de86a298..f182f0d3 100644 --- a/HydroEVENTS.pri +++ b/HydroEVENTS.pri @@ -10,7 +10,9 @@ INCLUDEPATH += $$PWD/EVENTS/MPM INCLUDEPATH += $$PWD/EVENTS/Celeris INCLUDEPATH += $$PWD/EVENTS/Celeris/js INCLUDEPATH += $$PWD/EVENTS/NOAA -INCLUDEPATH += $$PWD/EVENTS/SimpleWaves +INCLUDEPATH += $$PWD/EVENTS/StochasticWaveModel +INCLUDEPATH += $$PWD/EVENTS/StochasticWaveModel/include +INCLUDEPATH += $$PWD/EVENTS/StochasticWaveModel/src INCLUDEPATH += $$PWD/EVENTS/Common INCLUDEPATH += $$PWD/SlidingStackedWidget SOURCES += \ @@ -64,7 +66,8 @@ SOURCES += \ $$PWD/EVENTS/Celeris/WebGPU.cpp \ $$PWD/EVENTS/Celeris/volumetric.cpp \ $$PWD/EVENTS/NOAA/DigitalCoast.cpp \ - $$PWD/EVENTS/SimpleWaves/SimpleWaves.cpp \ + $$PWD/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp \ + $$PWD/EVENTS/StochasticWaveModel/src/Jonswap.cpp \ $$PWD/EVENTS/WaveDigitalFlume/WaveDigitalFlume.cpp \ $$PWD/EVENTS/Common/projectsettings.cpp \ $$PWD/EVENTS/Common/bathymetry.cpp @@ -121,7 +124,8 @@ HEADERS += \ $$PWD/EVENTS/Celeris/WebGPU.h \ $$PWD/EVENTS/Celeris/volumetric.h \ $$PWD/EVENTS/NOAA/DigitalCoast.h \ - $$PWD/EVENTS/SimpleWaves/SimpleWaves.h \ + $$PWD/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h \ + $$PWD/EVENTS/StochasticWaveModel/include/Jonswap.h \ $$PWD/EVENTS/WaveDigitalFlume/WaveDigitalFlume.h \ $$PWD/EVENTS/Common/projectsettings.h \ $$PWD/EVENTS/Common/bathymetry.h \ diff --git a/WorkflowAppHydroUQ.cpp b/WorkflowAppHydroUQ.cpp index 87ee356d..6c441463 100644 --- a/WorkflowAppHydroUQ.cpp +++ b/WorkflowAppHydroUQ.cpp @@ -108,6 +108,7 @@ UPDATES, ENHANCEMENTS, OR MODIFICATIONS. #include #include #include +#include #include #include #include @@ -272,16 +273,16 @@ WorkflowAppHydroUQ::setMainWindow(MainWindowWorkflowApp* window) { theDialog->showTool("Digital Twin (MPM)"); }); - // DigitalCoast *miniDC = new DigitalCoast(); - // QString appNameDC = "DigitalCoast-1.0.0"; // Frontera - // QString systemNameDC = "frontera"; - // QList queuesDC; queuesDC << "rtx" << "rtx-dev"; // These are later changed to "normal" and "fast" in the tool based on number of cores/processors? Should fix this - // SC_RemoteAppTool *miniDCTool = new SC_RemoteAppTool(appNameDC, queuesDC, theRemoteService, miniDC, theToolDialog); - // theToolDialog->addTool(miniDCTool, "Sea-Level Rise (NOAA Digital Coast)"); - // QAction *showDC = toolsMenu->addAction("Sea-Level Rise (&NOAA Digital Coast)"); - // connect(showDC, &QAction::triggered, this,[this, theDialog=theToolDialog, miniD = miniDCTool] { - // theDialog->showTool("Sea-Level Rise (NOAA Digital Coast)"); - // }); + DigitalCoast *miniDC = new DigitalCoast(); + QString appNameDC = "DigitalCoast-1.0.0"; // Frontera + QString systemNameDC = "frontera"; + QList queuesDC; queuesDC << "rtx" << "rtx-dev"; // These are later changed to "normal" and "fast" in the tool based on number of cores/processors? Should fix this + SC_RemoteAppTool *miniDCTool = new SC_RemoteAppTool(appNameDC, queuesDC, theRemoteService, miniDC, theToolDialog); + theToolDialog->addTool(miniDCTool, "Sea-Level Rise (NOAA Digital Coast)"); + QAction *showDC = toolsMenu->addAction("Sea-Level Rise (&NOAA Digital Coast)"); + connect(showDC, &QAction::triggered, this,[this, theDialog=theToolDialog, miniD = miniDCTool] { + theDialog->showTool("Sea-Level Rise (NOAA Digital Coast)"); + }); Celeris *miniCeleris = new Celeris(); QString appNameCeleris = "Celeris-1.0.0"; // Frontera From 5c5e2622dd8cd53e8496c38f4d138cec09d46566 Mon Sep 17 00:00:00 2001 From: JustinBonus Date: Wed, 15 May 2024 23:26:57 -0700 Subject: [PATCH 5/5] Workng deterministic local run of Stochastic Wave Model EVT (JONSWAP) --- EDP/HydroEDP_Selection.cpp | 2 +- EVENTS/HydroEventSelection.cpp | 5 ++--- .../StochasticWaveModel/include/StochasticWaveInput.h | 4 ++++ EVENTS/StochasticWaveModel/src/Jonswap.cpp | 10 ++++++++-- EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp | 5 +++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/EDP/HydroEDP_Selection.cpp b/EDP/HydroEDP_Selection.cpp index f682056d..78d9a80f 100644 --- a/EDP/HydroEDP_Selection.cpp +++ b/EDP/HydroEDP_Selection.cpp @@ -120,7 +120,7 @@ HydroEDP_Selection::HydroEDP_Selection(QWidget *parent) theStackedWidget->addWidget(theStandardStormSurgeEDPs); theStackedWidget->addWidget(theUserDefinedEDPs); theStackedWidget->addWidget(theStandardEDPs); - theStackedWidget->setCurrentIndex(4); + theStackedWidget->setCurrentIndex(0); layout->addWidget(theStackedWidget); this->setLayout(layout); diff --git a/EVENTS/HydroEventSelection.cpp b/EVENTS/HydroEventSelection.cpp index 8cb8a1aa..1efccdab 100644 --- a/EVENTS/HydroEventSelection.cpp +++ b/EVENTS/HydroEventSelection.cpp @@ -534,9 +534,8 @@ bool HydroEventSelection::copyFiles(QString &destDir) { bool HydroEventSelection::supportsLocalRun() { - // return theCurrentEvent->supportsLocalRun(); - // if theCurrentEvent - return false; + if (theCurrentEvent != 0) + return theCurrentEvent->supportsLocalRun(); } bool diff --git a/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h b/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h index 91131d0a..1522e98e 100644 --- a/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h +++ b/EVENTS/StochasticWaveModel/include/StochasticWaveInput.h @@ -101,6 +101,10 @@ class StochasticWaveInput : public SimCenterAppWidget { */ bool outputAppDataToJSON(QJsonObject& rvObject); + + bool supportsLocalRun() override; + + signals: void sendErrorMessage(QString message); diff --git a/EVENTS/StochasticWaveModel/src/Jonswap.cpp b/EVENTS/StochasticWaveModel/src/Jonswap.cpp index 3b90bbcd..55fa8317 100644 --- a/EVENTS/StochasticWaveModel/src/Jonswap.cpp +++ b/EVENTS/StochasticWaveModel/src/Jonswap.cpp @@ -121,8 +121,10 @@ bool Jonswap::outputAppDataToJSON(QJsonObject& jsonObject) { bool result = true; jsonObject["Application"] = "StochasticWaveJonswap"; - jsonObject["EventClassification"] = "Hydro"; + // jsonObject["EventClassification"] = "Hydro"; + // jsonObject["Application"] = "StochasticWindWittigSinha"; + jsonObject["EventClassification"] = "Wind"; // squirel in the application data selection text QJsonObject appData; jsonObject["ApplicationData"] = appData; @@ -139,7 +141,11 @@ bool Jonswap::outputToJSON(QJsonObject& jsonObject) { bool result = true; jsonObject["type"] = "StochasticWaveJonswap"; - jsonObject["EventClassification"] = "Hydro"; + // jsonObject["type"] = "StochasticWindWittigSinha"; + + // jsonObject["EventClassification"] = "Hydro"; + jsonObject["EventClassification"] = "Wind"; + dragCoefficient->outputToJSON(jsonObject, QString("dragCoefficient")); gustWindSpeed->outputToJSON(jsonObject, QString("gustSpeed")); jsonObject.insert("exposureCategory",exposureCategory->currentText()); diff --git a/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp b/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp index 0456f84b..e48b41fb 100644 --- a/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp +++ b/EVENTS/StochasticWaveModel/src/StochasticWaveInput.cpp @@ -144,6 +144,11 @@ bool StochasticWaveInput::inputAppDataFromJSON(QJsonObject& jsonObject) { return true; } +bool StochasticWaveInput::supportsLocalRun() { + // TODO: Check if the selected model supports local run + return true; +} + void StochasticWaveInput::modelSelectionChanged(const QString& model) { // Switch the model description and form layout based on model selection