From 77bd6ca692be0d3666f988ec05a5e80e876dd5d7 Mon Sep 17 00:00:00 2001 From: DavidAKopriva <85404032+DavidAKopriva@users.noreply.github.com> Date: Thu, 9 Sep 2021 08:38:33 -0700 Subject: [PATCH 001/164] Add HQMtool folder Add the code, documentation and examples to the repo for the HQMTool interactive front end. --- HQMTool/Demo/AllFeatures.control | 112 ++++ HQMTool/Doc/CheatSheet.md | 64 +++ HQMTool/Doc/HQMTool.md | 501 ++++++++++++++++++ HQMTool/Doc/iceCreamCone.png | Bin 0 -> 436345 bytes HQMTool/HQMTool.jl | 143 +++++ .../ControlFile/ControlFileOperations.jl | 316 +++++++++++ HQMTool/Source/Curves/CurveOperations.jl | 243 +++++++++ HQMTool/Source/Curves/Spline.jl | 131 +++++ HQMTool/Source/Mesh/Meshing.jl | 53 ++ HQMTool/Source/Misc/DictionaryOperations.jl | 89 ++++ HQMTool/Source/Misc/NotificationCenter.jl | 107 ++++ HQMTool/Source/Model/Geometry.jl | 93 ++++ HQMTool/Source/Project/BackgroundGridAPI.jl | 265 +++++++++ HQMTool/Source/Project/ControlInputAPI.jl | 60 +++ HQMTool/Source/Project/CurvesAPI.jl | 450 ++++++++++++++++ HQMTool/Source/Project/Generics.jl | 164 ++++++ HQMTool/Source/Project/ModelAPI.jl | 427 +++++++++++++++ HQMTool/Source/Project/Project.jl | 409 ++++++++++++++ .../Source/Project/RefinementRegionsAPI.jl | 476 +++++++++++++++++ HQMTool/Source/Project/RunParametersAPI.jl | 190 +++++++ HQMTool/Source/Project/SmootherAPI.jl | 118 +++++ HQMTool/Source/Project/Undo.jl | 142 +++++ HQMTool/Source/Viz/VizMesh.jl | 78 +++ HQMTool/Source/Viz/VizProject.jl | 194 +++++++ 24 files changed, 4825 insertions(+) create mode 100644 HQMTool/Demo/AllFeatures.control create mode 100644 HQMTool/Doc/CheatSheet.md create mode 100644 HQMTool/Doc/HQMTool.md create mode 100644 HQMTool/Doc/iceCreamCone.png create mode 100644 HQMTool/HQMTool.jl create mode 100644 HQMTool/Source/ControlFile/ControlFileOperations.jl create mode 100644 HQMTool/Source/Curves/CurveOperations.jl create mode 100644 HQMTool/Source/Curves/Spline.jl create mode 100644 HQMTool/Source/Mesh/Meshing.jl create mode 100644 HQMTool/Source/Misc/DictionaryOperations.jl create mode 100644 HQMTool/Source/Misc/NotificationCenter.jl create mode 100644 HQMTool/Source/Model/Geometry.jl create mode 100644 HQMTool/Source/Project/BackgroundGridAPI.jl create mode 100644 HQMTool/Source/Project/ControlInputAPI.jl create mode 100644 HQMTool/Source/Project/CurvesAPI.jl create mode 100644 HQMTool/Source/Project/Generics.jl create mode 100644 HQMTool/Source/Project/ModelAPI.jl create mode 100644 HQMTool/Source/Project/Project.jl create mode 100644 HQMTool/Source/Project/RefinementRegionsAPI.jl create mode 100644 HQMTool/Source/Project/RunParametersAPI.jl create mode 100644 HQMTool/Source/Project/SmootherAPI.jl create mode 100644 HQMTool/Source/Project/Undo.jl create mode 100644 HQMTool/Source/Viz/VizMesh.jl create mode 100644 HQMTool/Source/Viz/VizProject.jl diff --git a/HQMTool/Demo/AllFeatures.control b/HQMTool/Demo/AllFeatures.control new file mode 100644 index 00000000..880bb474 --- /dev/null +++ b/HQMTool/Demo/AllFeatures.control @@ -0,0 +1,112 @@ +\begin{MODEL} + \begin{OUTER_BOUNDARY} + \begin{END_POINTS_LINE} + name = B1 + xEnd = [20.0,-5,0.0] + xStart = [-20.0,-5.0,0.0] + \end{END_POINTS_LINE} + \begin{END_POINTS_LINE} + name = B2 + xEnd = [0.0,25.28,0.0] + xStart = [20.0,-5.0,0.0] + \end{END_POINTS_LINE} + \begin{END_POINTS_LINE} + name = B3 + xEnd = [-20.0,-5.0,0.0] + xStart = [0.0,25.28,0.0] + \end{END_POINTS_LINE} + \end{OUTER_BOUNDARY} + \begin{INNER_BOUNDARIES} + \begin{CHAIN} + name = Arc + \begin{CIRCULAR_ARC} + units = degrees + name = InnerCircle1 + radius = 1.0 + start angle = 0.0 + center = [-12.0,-1.5,0.0] + end angle = 360.0 + \end{CIRCULAR_ARC} + \end{CHAIN} + \begin{CHAIN} + name = InnerSpline + \begin{SPLINE_CURVE} + name = Spline + nKnots = 26 + \begin{SPLINE_DATA} + 0.0 -3.5 3.5 0.0 + 0.03846153846153846 -3.2 5.0 0.0 + 0.07692307692307693 -2.0 6.0 0.0 + 0.115384615384615 1.0 6.0 0.0 + 0.153846153846154 2.0 5.0 0.0 + 0.192307692307692 3.0 4.0 0.0 + 0.230769230769231 5.0 4.0 0.0 + 0.269230769230769 6.0 5.0 0.0 + 0.307692307692308 7.0 7.0 0.0 + 0.346153846153846 8.0 8.0 0.0 + 0.384615384615385 9.0 8.0 0.0 + 0.423076923076923 10.0 7.0 0.0 + 0.461538461538462 11.0 5.0 0.0 + 0.5 11.0 3.0 0.0 + 0.538461538461539 10.0 2.0 0.0 + 0.576923076923077 9.0 1.0 0.0 + 0.615384615384615 7.0 1.0 0.0 + 0.653846153846154 5.0 1.0 0.0 + 0.692307692307692 3.0 1.0 0.0 + 0.730769230769231 1.0 0.0 0.0 + 0.769230769230769 0.0 -1.0 0.0 + 0.807692307692308 -1.0 -1.0 0.0 + 0.846153846153846 -2.0 -0.8 0.0 + 0.884615384615385 -2.5 0.0 0.0 + 0.923076923076923 -3.0 1.0 0.0 + 1.0 -3.5 3.5 0.0 + \end{SPLINE_DATA} + \end{SPLINE_CURVE} + \end{CHAIN} + \begin{CHAIN} + name = InnerCircle2 + \begin{PARAMETRIC_EQUATION_CURVE} + name = Circle1 + yEqn = f(t) = 17.0 + 1.5*sin(2*pi*t) + zEqn = z(t) = 0.0 + xEqn = f(t) = 1.5*cos(2*pi*t) + \end{PARAMETRIC_EQUATION_CURVE} + \end{CHAIN} + \end{INNER_BOUNDARIES} +\end{MODEL} +\begin{CONTROL_INPUT} + \begin{REFINEMENT_REGIONS} + \begin{REFINEMENT_CENTER} + name = center + w = 0.5 + x0 = [9.0,-3.0,0.0] + type = smooth + h = 0.1 + \end{REFINEMENT_CENTER} + \begin{REFINEMENT_LINE} + name = line + x1 = [2.0,14.0,0.0] + w = 0.5 + x0 = [-6.0,9.0,0.0] + type = smooth + h = 0.2 + \end{REFINEMENT_LINE} + \end{REFINEMENT_REGIONS} + \begin{SPRING_SMOOTHER} + smoothing type = LinearAndCrossbarSpring + smoothing = ON + number of iterations = 25 + \end{SPRING_SMOOTHER} + \begin{BACKGROUND_GRID} + background grid size = [3.0,3.0,0.0] + \end{BACKGROUND_GRID} + \begin{RUN_PARAMETERS} + mesh file name = Demo/AllFeatures.mesh + plot file format = skeleton + plot file name = Demo/AllFeatures.tec + stats file name = none + mesh file format = ISM-V2 + polynomial order = 4 + \end{RUN_PARAMETERS} +\end{CONTROL_INPUT} +\end{FILE} diff --git a/HQMTool/Doc/CheatSheet.md b/HQMTool/Doc/CheatSheet.md new file mode 100644 index 00000000..05763e8a --- /dev/null +++ b/HQMTool/Doc/CheatSheet.md @@ -0,0 +1,64 @@ +#HQMTool CheatSheet + +Workflow: + +1. Create a project +2. Add boundary curves +4. Add a background grid +3. Add manual refinement (if desired) +5. Generate mesh + +### Project + + p = newProject(,) + +### Plotting + + plotProject!(p,options) + updatePlot!(p,options) + +### Curves + + c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* + c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* + c = new(name, xEqn, yEqn, zEqn ) *Parametric equation* + c = new(name, dataFile) *Spline* + c = new(name, nKnots, knotsMatrix) *also Spline* + +### Manual Refinement + + r = newRefinementCenter(name, center, gridSize, radius ) + r = newRefinementLine(name,type, startPoint, endPoint, gridSize, width ) +### Adding to a Project + + add!(p, c) *Add outer boundary curve* + add!(p, c, ) *add curve to an inner boundary* + add!(p, r) *Add refinement region* + + addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* + addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* + +### Accessing items + + crv = get(p,curveName) *Get a curve in the outer boundary* + crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* + indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* + r = getRefinementRegion(p, name) + +### Removing from Project + + removeOuterboundary!(p) *Entire outer boundary curve* + removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve + remove!(p, name) *Curve in outer boundary* + remove!(p, name, innerBoundaryName) *Curve in inner boundary* + removeRefinementRegion!(p, name) + +### Editing items + +All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. + +### Meshing + + generateMesh(p) + removeMesh!(p) + \ No newline at end of file diff --git a/HQMTool/Doc/HQMTool.md b/HQMTool/Doc/HQMTool.md new file mode 100644 index 00000000..8b2e8c40 --- /dev/null +++ b/HQMTool/Doc/HQMTool.md @@ -0,0 +1,501 @@ +#HQMTool +HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. + +## Contents + +1. [Introduction](#introduction) +2. [Basic Moves](#basicMoves) +3. [HQMTool API](#API) + 1. [Project Creation and Saving](#Project) + 2. [Plotting](#Plotting) + 3. [Modifying/Editing a Project](#EditingProject) + 4. [Controlling the Mesh Generation Process](#Control) + 1. [Editing the Run Parameters](#RunParameters) + 2. [Changing the output file names](#OutputFiles) + 3. [Adding the background grid](#BackgroundGrid) + 4. [Smoothing Operations](#Smoother) + 5. [Manual Refinement](#ManualRefinement) + 5. [Boundary Curves](#BoundaryCurves) + 1. [Adding and Removing Outer and Inner Boundaries](#AddingCurves) + 2. [Defining Curves](#DefiningCurves) + 3. [Editing Curves](#EditingCurves) + 6. [Undo/Redo](#Undo) +4. [Advanced](#Advanced) + +## Introduction + +HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. +To see that example, run + + runDemo() + +The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The script is + + function iceCreamCone(folder::String) + # + # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, + # written to `path`. This version uses generic versions of + # the API. + # + p = newProject("IceCreamCone",path) + # + # Outer boundary + # + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) + # + # Inner boundary + # + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) # A line + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") # An arc + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) # A line + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") + # + # Set some control RunParameters to overwrite the defaults + # + setPolynomialOrder!(p,4) + setPlotFileFormat!(p,"sem") + # + # To mesh, a background grid is needed + # + addBackgroundGrid!(p, [0.1,0.1,0.0]) + # + # Show the model and grid + # + plotProject!(p, MODEL+GRID) + # + # Generate the mesh and plot + # + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + updatePlot!(p, MODEL+MESH) + + return p + end + +The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. + +To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, if desired. As in HOHQMesh, there are four curve classes currently operational: + +- Parametric equations +- Splines +- Lines defined by their end points +- Circular arcs + +In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. + +Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. + +For convenience, `newProject` will generate default run parameters, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). + +One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extend of the domain to be meshed, so only the mesh size needs to be specified using + + addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + +The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. + +The script finishes by generating the quad mesh and plotting the results, as shown below +![](iceCreamCone.png) It also returns the project so that it can be edited further, if desired. + +To save a control file for HOHQMesh, simply invoke + + saveProject(proj::Project,outFile::String) + +where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. + +Methods are available to edit a model. For example to move the center of the outer boundary + +## Basic Moves + +To create generate a mesh you + +- [Create a project](#newProject) + + p = newProject(,) + +- [Create inner and outer boundary curves](#DefiningCurves) + + c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) + c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) + c = new(, xEqn, yEqn, zEqn ) (Parametric equation) + c = new(, dataFile) (Spline) + c = new(, nKnots, knotsMatrix) (also Spline) + +- [Add curves](#AddingCurves) to build the model to see what you have added, + + add!(p, ) (Add outer boundary curve) + add!(p, , ) (add curve to an inner boundary) + +- To [visualize](#Plotting) the project's model, + + plotProject(p,MODEL) + + To update the plot at any time, use + + updatePlot!(p, options) + + Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) + +- Set the [background grid](#(#BackgroundGrid)) + + addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) + *OR* + addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) + + addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) + +- [Adjust parameters](#RunParameters), if desired (e.g.) + + setPolynomialOrder!(p,order) + +- Generate the mesh + + generateMesh(p) + +The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. + + +#HQMTool API +# Project Creation and Saving + +### New Project + + (Return:Project) proj = newProject(name::String, folder::String) + +The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). + +### Opening an existing project file + + (Return:Project) proj = openProject(fileName::String, folder::String) + + +### Saving a project + + saveProject(proj::Project) + +writes a control file to the folder designated when creating the new project. It can be read in again with OpenProject. + +# Plotting + +### Plotting a Project + + plotProject(proj::Project, options) + +The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show where [manual refinement](#ManualRefinement) is added. + +If the model is modified and you want to re-plot with the new values, invoke + + updatePlot!(proj::Project, options) + +but genrally the plot will be updated automatically as you build the model. + + +# Modifying/Editing a Project + +### Setting the name of a project + +The project name is the name under which the mesh, plot, statistics and control files will be written. + + setName!(proj::Project,name::String) + + +### Getting the current name of a Project + + [Return:String] getName(proj::Project) + +# Controlling the Mesh Generation Process + +### Editing the Run Parameters + +The run parameters can be enquired and set with these getter/setter pairs: + + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) + [Return:Int] getPolynomialOrder(proj::Project) + [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) + [Return:String] getMeshFileFormat(proj::Project) + [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) + [Return:String] getPlotFileFormat(proj::Project) + +The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite elemnt represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** + +### Changing the output file names + +By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with + + [Return:nothing] setName!(proj::Project,name::String) + [Return:String] getName(proj::Project) + [Return:nothing] setFolder!(proj::Project,folder::String) + [Return:String] getFolder(proj::Project) + +### Adding the background grid + +There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. + + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + +Use one of the first two if there is no outer boundary. With the first, a rectangular outer boundary will be created of extent [x0[1], x0[1]+N dx[1]]X[x0[2], x0[2]+N*dx[2]]. The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. The arrays `x0`, `dx`, `N`, `bgSize` are all vectors [ *, \*, \*] giving the x, y, and z components. + +### Smoothing Operations + +A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. + +To change the defaults, the smoother parameters can be set/enquired with the functions + + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) + [Return:String] getSmoothingStatus(proj::Project) + [Return:nothing] setSmoothingType!(proj::Project, type::String) + [Return:String] getSmoothingType(proj::Project) + [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) + [Return:Int] getSmoothingIterations(proj::Project) + +`status` is either "ON" or "OFF". + +To remove the smoother altogether, + + [Return:nothing] removeSpringSmoother!(proj::Project) + +### Manual Refinement + +Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. + +To create a refinement center, + + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, + x0::Array{Float64}, h::Float64, + w::Float64 ) + +where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. + +Similarly, one can create a `RefinementLine`, + + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64 ) + +where `x0` is the start postition and `x1` is the end of the line. + +To add a refinement region to the project, + + [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) + +To get the indx'th refinement region from the project, or to get + a refinement region with a given name, use + + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) + +Finally, to get a list of all the refinement regions, + + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) + +A refinement region can be edited by using the following + + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) + [Return:String] getRefinementType(r::Dict{String,Any}) + [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) + [Return:nothing] setRefinementGridSize!(r::Dict{String,Any},h::Float64) + [Return:float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) + [Return:float64] getRefinementWidth(r::Dict{String,Any}) + +where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. + +To further edit a `RefinementLine`, use the methods + + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) + [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) + +# Boundary Curves + +### Adding Outer and Inner Boundaries + +- Adding an outer boundary curve + + Using the curve creation routines, described in the next section below, create curves in sucessive order counter-clockwise along the outer boundary and add them to the outer boundary curve using + + [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + Generic: add!(...) + + `crv` is the dictionary that represents the curve. + +Example: + + add!(p,circ) + +- Adding an inner boundary curve + + [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + Generic: add!(...) + +Example: + + add!(p,cone1,"IceCreamCone") + +To edit curves they can be accessed by name: + + [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + Generic: get(...) + [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) + Generic: get(...) + +- Deleting boundary curves + + [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) + Generic: remove!(...) + [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + Generic: remove!(...) + +## Defining Curves + +Four curve types can be added to the outer and inner boundary curve chains. They are + +- parametricEquation +- endPointsLine +- circularArc +- spline + + +### Parametric Equations + +- Creating new + + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + Generic: new(...) + + Returns a new parametric equation. Equations must be of the form + + () = ... + + The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. + + Example: + + x(s) = 2.0 + 3*cos(2*pi*s)^2 + + The z-Equation is optional, but for now must define zero for z. + +### Line Defined by End Points + + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + Generic: new(...) + +The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should be zero and for now is ignored. + +Example: + + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) +### Circular Arc + + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) + Generic: new(...) + + The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". + +Example: + + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + +### Spline Curve + +A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. + + 9 + 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 + 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 + 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 + 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 + 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 + 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 + 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 + 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 + 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 + +or by constructing the Nx4 array supplying it to the new procedure. The constructors are + + [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + Generic: new(...) + [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) + Generic: new(...) + +If the curve is to be closed. The last point must be the same as the first. + +## Editing Curves + +You can determine the type of a curve by + + [Return:String] getCurveType(crv::Dict{String,Any}) + +For any of the curves, their name can be changed by + + setCurveName!(crv::Dict{String,Any}, name::String) + +and checked by + + getCurveName(crv::Dict{String,Any}) + +Otherwise there are special functions to change the parameters of curves + + [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) + [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + [Return:String] getXEqn(crv::Dict{String,Any}) + [Return:String] getYEqn(crv::Dict{String,Any}) + [Return:String] getZEqn(crv::Dict{String,Any}) + [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) + [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) + [Return:String] getArcUnits(arc::Dict{String,Any}) + [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) + [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) + [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) + [Return:Float64] getArcRadius(arc::Dict{String,Any}) + +## Undo/Redo + +The HQMTool has unlimited undo/redo for most actions. + +In interactive mode, actions can be undone by the commands + + [Return:String] undo() + [Return:String] redo() + +where the return string contains the name of the action performed. + +To find out what the next actions are, use + + [Return:String] undoName() + [Return:String] redoName() + +Finally, to clear the undo stack, use + + [Return:nothing] clearUndoRedo() + +# Advanced + +All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file diff --git a/HQMTool/Doc/iceCreamCone.png b/HQMTool/Doc/iceCreamCone.png new file mode 100644 index 0000000000000000000000000000000000000000..23511d2bc9342e0490b3c8cc01e6e67019f3b48f GIT binary patch literal 436345 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
(R3ztIK~x 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üq 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%0Dr(21&z%>XKL|t4bbV$aAGv@ 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�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 MlK#c)3%CCMFNR>_Y5)KL literal 0 HcmV?d00001 diff --git a/HQMTool/HQMTool.jl b/HQMTool/HQMTool.jl new file mode 100644 index 00000000..7d890306 --- /dev/null +++ b/HQMTool/HQMTool.jl @@ -0,0 +1,143 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using Base: CyclePadding, Int64, Float64, current_logger, parseint_preamble, String, Bool +using Printf +using HOHQMesh +#= + A program for reading, writing and plotting a model for HOHQMesh +=# +include("Source/Viz/VizMesh.jl") +include("Source/Misc/NotificationCenter.jl") +include("Source/Misc/DictionaryOperations.jl") +include("Source/Curves/Spline.jl") +include("Source/ControlFile/ControlFileOperations.jl") +include("Source/Curves/CurveOperations.jl") +include("Source/Project/Project.jl") +include("Source/Project/CurvesAPI.jl") +include("Source/Viz/VizProject.jl") +include("Source/Project/Undo.jl") +include("Source/Mesh/Meshing.jl") +include("Source/Project/Generics.jl") + +# +#---------------- FOR TESTING PURPOSES -------------------------------------- +# + +function runDemo() +#= + Reads in an existing control file, plots the boundary curves and generates + a mesh. +=# + p = openProject("AllFeatures.control", "Demo") + plotProject!(p,MODEL+REFINEMENTS+GRID) + println("Hit any key to continue and generate the mesh") + readline() + generateMesh(p) + return p +end + +function iceCreamConeVerbose(folder::String) +# +# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# written to `folder`. +# + p = newProject("IceCreamCone",folder) +# +# Outer boundary +# + circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + addCurveToOuterBoundary!(p,circ) +# +# Inner boundary +# + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p,cone1,"IceCreamCone") + addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") + addCurveToInnerBoundary!(p,cone2,"IceCreamCone") +# +# Set some control RunParameters to overwrite the defaults +# + setPolynomialOrder!(p,4) + setPlotFileFormat!(p,"sem") +# +# To mesh, a background grid is needed +# + addBackgroundGrid!(p, [0.5,0.5,0.0]) +# +# Show the model and grid +# + plotProject!(p, MODEL+GRID) +# +# Generate the mesh and plot +# + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + +return p +end + +function iceCreamCone(folder::String) + # + # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, + # written to `path`. + # + p = newProject("IceCreamCone",folder) + # + # Outer boundary + # + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) + # + # Inner boundary + # + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") + # + # To mesh, a background grid is needed + # + addBackgroundGrid!(p, [0.5,0.5,0.0]) + # + # Show the model and grid + # + plotProject!(p, MODEL+GRID) + # + # Generate the mesh and plot + # + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + return p +end diff --git a/HQMTool/Source/ControlFile/ControlFileOperations.jl b/HQMTool/Source/ControlFile/ControlFileOperations.jl new file mode 100644 index 00000000..2e38c2be --- /dev/null +++ b/HQMTool/Source/ControlFile/ControlFileOperations.jl @@ -0,0 +1,316 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +#= + ImportControlFile(fileName::String) + +The control file reader parses the control file and returns a Control file dictionary. + +@author: davidkopriva + +A Control file dictionary contains the keys + TYPE + CONTROL_INPUT + MODEL + +TYPE is a string naming the type (class) of object stored + +The CONTROL_INPUT contains the blocks + TYPE + RUN_PARAMETERS + MESH_PARAMETERS + SPRING_SMOOTHER + REFINEMENT_REGIONS + REFINEMENT_REGIONS contains a ["LIST"] of + REFINEMENT_CENTER + REFINEMENT_LINE + SCALE_TRANSFORMATION + ROTATION_TRANSFORMATION + SIMPLE_EXTRUSION + SIMPLE_ROTATION + SWEEP_ALONG_CURVE + +The MODEL dictionary contains the keys + TYPE + OUTER_BOUNDARY + OUTER_BOUNDARY contains a ["LIST"] of + PARAMETRIC_EQUATION_CURVE + SPLINE_CURVE + END_POINTS_LINE + CIRCULAR_ARC + INNER_BOUNDARIES + The INNER_BOUNDARIES block contains a ["LIST"] of + CHAIN + SWEEP_CURVE + SWEEP_SCALE_FACTOR + TOPOGRAPHY + +A CHAIN block contains a ["LIST"] of + PARAMETRIC_EQUATION_CURVE + SPLINE_CURVE + END_POINTS_LINE + CIRCULAR_ARC + +A PARAMETRIC_EQUATION_CURVE dictionary contains the keys + TYPE + name + xEqn + yEqn + zEqn + +=# + +# Four objects store their members as lists rather than +# as dictionaries + +blocksThatStoreLists = Set(["OUTER_BOUNDARY", + "REFINEMENT_REGIONS" , + "INNER_BOUNDARIES", + "CHAIN"]) + +blockNameStack = [] +blockRegex = r"(?<=\{).+?(?=\})" +# +#--------------- MAIN ENTRY ----------------------------------------------- +# +function ImportControlFile(fileName::String) + controlDict = Dict{String,Any}() + open(fileName,"r") do controlFile + performImport(controlDict, controlFile) + end + return controlDict +end + +function WriteControlFile(controlDict::Dict{String,Any}, fileName::String) + open(fileName,"w") do controlFile + indent = "" + WriteDictionary(controlDict, controlFile, indent) + println(controlFile,"\\end{FILE}") + end +end +# +#------------- END MAIN ENTRY ------------------------------------------ +# +function performImport(collection, f::IOStream) + + for line in eachline(f) +# +# ---------------- +# Start of a block +# ---------------- +# + if occursin("begin{",line) + blockNameMatch = match(blockRegex,line) + if blockNameMatch === nothing + error("Block name not found in string: " * line) + else # Start new collection + blockName = blockNameMatch.match + push!(blockNameStack, blockName) +# +# A SPLINE_DATA block is special and is read in separately +# into an array and saved in the spline curve dictionary +# + if blockName == "SPLINE_DATA" + ImportSplineData( collection, f) + continue + end + + newBlock = Dict{String,Any}() + newBlock["TYPE"] = blockName + addToCollection(collection, blockName, newBlock) +# +# Some blocks store items in a list +# + if in(blockName, blocksThatStoreLists) + newBlock["LIST"] = Dict{String,Any}[] +# +# If the block defines a chain, get its name +# + if blockName == "CHAIN" + nextLine = readline(f) + kvp = keyAndValueOnLine(nextLine) + if kvp === nothing + error("Key-value pair not found in string: " * nextLine) + end + addToCollection(newBlock,kvp[1],kvp[2]) + end + performImport(newBlock["LIST"],f) + else + performImport(newBlock,f) + end + end +# +# -------------- +# End of a block +# -------------- +# + elseif occursin("end{",line) + blockNameMatch = match(blockRegex,line) + blockName = blockNameMatch.match + if blockName == "FILE" + return + end + if length(blockNameStack) == 0 + error("Extra end statement found: " * line) + end + if blockNameMatch === nothing + error("Block name not found in string: " * line) + else + stackValue::String = blockNameStack[end] + if cmp(blockName,stackValue) == 0 + pop!(blockNameStack) + else + error("Block name end $blockName does not match current block $stackValue") + end + if blockName == "SPLINE_DATA" + continue + else + return + end + end +# +# ---------------------- +# Comment or blank lines +# ---------------------- +# + elseif isempty(line) + continue + elseif line[1] == '%' + continue +# +# ------------------------- +# Block body key-value pair +# ------------------------- +# + else + kvp = keyAndValueOnLine(line) + if kvp === nothing + error("Key-value pair not found in string: " * line) + end + addToCollection(collection,kvp[1],kvp[2]) + end + end +end +# +#-------------------------------------------------------------------------------------- +# +function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::String) + + deepIndent = " " * indent + for (key, value) in controlDict + if isa(value, AbstractDict) + println(f,indent,"\\begin{$key}") + if in(key,blocksThatStoreLists) + list = value["LIST"] + StepThroughList(list,f, deepIndent) + else + WriteDictionary(value,f, deepIndent) + end + println(f,indent,"\\end{$key}") + elseif isa(value, AbstractString) + if key != "TYPE" + println(f,indent,"$key = $value") + end + elseif isa(value, AbstractArray) + if key == "LIST" + StepThroughList(value,f, deepIndent) + elseif key == "SPLINE_DATA" + println(f,indent,"\\begin{$key}") + arraySize = size(value) + for j = 1:arraySize[1] + println(f,deepIndent, " ", value[j,1], " ", value[j,2], " ", value[j,3], " ", value[j,4]) + end + println(f,indent,"\\end{$key}") + end + end + end +end +# +#-------------------------------------------------------------------------------------- +# +function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) + deepIndent = " " * indent + for dict in lst + dtype = dict["TYPE"] + println(f,indent, "\\begin{$dtype}") + WriteDictionary(dict,f, deepIndent) + println(f,indent, "\\end{$dtype}") + end +end +# +#-------------------------------------------------------------------------------------- +# +function keyAndValueOnLine(s) + indxOfEqual = findfirst("=",s) + if indxOfEqual === nothing + return nothing + end + key = strip(s[1:indxOfEqual.start-1],[' ','\t']) + value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) + return (key,value) +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::AbstractString) + dict[k] = v +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(c::Array, k::AbstractString, v::Any) + push!(c,v) +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::Dict{String,Any}) + dict[k] = v +end +# +#-------------------------------------------------------------------------------------- +# +function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) + + if !haskey(splineDict, "nKnots") + @warn "Spline block must define nKnots before SPLINE_DATA. Skipping..." + line = "" + while !occursin("end{SPLINE_DATA",line) #BUG This will read one too many lines + line = readline(f) + end + end + + knotString = splineDict["nKnots"] + nKnots = parse(Int64,knotString) + splineDataArray = zeros(Float64,nKnots,4) + for i = 1:nKnots + currentLine = split(readline(f)) + for j = 1:4 + splineDataArray[i,j] = parse(Float64,currentLine[j]) + end + end + splineDict["SPLINE_DATA"] = splineDataArray +end diff --git a/HQMTool/Source/Curves/CurveOperations.jl b/HQMTool/Source/Curves/CurveOperations.jl new file mode 100644 index 00000000..a7de2eba --- /dev/null +++ b/HQMTool/Source/Curves/CurveOperations.jl @@ -0,0 +1,243 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using Base: String, Int64, Float64 + +argRegex = r"(?<=\().+?(?=\))" + +function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Array{Float64}, points::Array{Float64,2}) + fctr::Float64 = 1.0 + if units == "degrees" + fctr = pi/180.0 + end + + theta::Float64 = 0.0 + for i = 1:length(t) + theta = thetaStart + (thetaEnd - thetaStart)*t[i] + points[i,1] = center[1] + r*cos(theta*fctr) + points[i,2] = center[2] + r*sin(theta*fctr) + end +end + +function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, + units::AbstractString, t::Float64, point::Array{Float64}) + fctr::Float64 = 1.0 + if units == "degrees" + fctr = pi/180.0 + end + theta = thetaStart + (thetaEnd - thetaStart)*t + point[1] = center[1] + r*cos(theta*fctr) + point[2] = center[2] + r*sin(theta*fctr) +end + +function endPointsLineCurvePoints(xStart::Array{Float64}, xEnd::Array{Float64}, t::Array{Float64}, points::Array{Float64}) + for i = 1:length(t) + points[i,1:2] = xStart[1:2] + t[i]*(xEnd[1:2] - xStart[1:2]) + end +end + +function endPointsLineCurvePoint(xStart::Array{Float64}, xEnd::Array{Float64}, t::Float64, point::Array{Float64}) + point[1:2] = xStart[1:2] + t*(xEnd[1:2] - xStart[1:2]) +end + +function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Float64,2}) + + argPart,eqString = keyAndValueFromString(xEqn) + xArgM = match(argRegex,argPart) + xArg = Symbol(xArgM.match) + ex = Meta.parse(eqString) + + argPart,eqString = keyAndValueFromString(yEqn) + yArgM = match(argRegex,argPart) + yArg = Symbol(yArgM.match) + ey = Meta.parse(eqString) + + for i = 1:length(t) + points[i,1] = evalWithDict(ex,Dict(xArg=> t[i])) + points[i,2] = evalWithDict(ey,Dict(yArg=> t[i])) + end +end + +function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) + + argPart,eqString = keyAndValueFromString(xEqn) + xArgM = match(argRegex,argPart) + xArg = Symbol(xArgM.match) + ex = Meta.parse(eqString) + + argPart,eqString = keyAndValueFromString(yEqn) + yArgM = match(argRegex,argPart) + yArg = Symbol(yArgM.match) + ey = Meta.parse(eqString) + + point[1] = evalWithDict(ex,Dict(xArg=> t[i])) + point[2] = evalWithDict(ey,Dict(yArg=> t[i])) + +end + +function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Array{Float64,2}) + + xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) + ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) + + sz = size(points) + nPts = sz[1] + t = 0.0 + for i = 1:nPts + t = (i-1)/(nPts-1) + points[i,1] = evalSpline(xSpline,t) + points[i,2] = evalSpline(ySpline,t) + end +end + +function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::Array{Float64}) + + xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) + ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) + + point[1] = evalSpline(xSpline,t) + point[2] = evalSpline(ySpline,t) +end + +function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) + ex = Meta.parse(s) + assignments = [:($sym = $val) for (sym,val) in locals] + eval(:(let $(assignments...); $ex; end)) +end + +function evalWithDict(ex::Expr, locals::Dict{Symbol}) + assignments = [:($sym = $val) for (sym,val) in locals] + eval(:(let $(assignments...); $ex; end)) +end + +function curvePoints(crvDict::Dict{String,Any}, N::Int) + + curveType::String = crvDict["TYPE"] + + if curveType == "PARAMETRIC_EQUATION_CURVE" + xEqn = crvDict["xEqn"] + yEqn = crvDict["yEqn"] + + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + peEquationCurvePoints(xEqn,yEqn,t,x) + elseif curveType == "END_POINTS_LINE" + xStart = realArrayForKeyFromDictionary("xStart",crvDict) + xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) + x = zeros(Float64,3,2) + t = zeros(Float64,3) + for i = 1:3 + t[i] = (i-1)/2.0 + end + + endPointsLineCurvePoints(xStart,xEnd,t,x) + elseif curveType == "CIRCULAR_ARC" + center = realArrayForKeyFromDictionary("center",crvDict) + radius = realForKeyFromDictionary("radius",crvDict) + startAngle = realForKeyFromDictionary("start angle",crvDict) + endAngle = realForKeyFromDictionary("end angle",crvDict) + units = crvDict["units"] + + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + + arcCurvePoints(center,radius,startAngle,endAngle,units,t,x) + elseif curveType == "SPLINE_CURVE" + nKnots = intForKeyFromDictionary("nKnots",crvDict) + splineData = crvDict["SPLINE_DATA"] + + M = max(N,nKnots*2) + x = zeros(Float64,M+1,2) + t = zeros(Float64,M+1) + for i = 1:M+1 + t[i] = (i-1)/M + end + + splineCurvePoints(nKnots,splineData,x) + else + + end + return x +end + +function chainPoints(chain::Array{Dict{String,Any}}, N::Int) + + x = Any[] + + for crvDict in chain + push!(x,curvePoints(crvDict,N)) + end + return x +end + +function curvePoint(crvDict::Dict{String,Any}, t::Float64) + + curveType::String = crvDict["TYPE"] + + if curveType == "PARAMETRIC_EQUATION_CURVE" + xEqn = crvDict["xEqn"] + yEqn = crvDict["yEqn"] + x = zeros(Float64,3) + peEquationCurvePoint(xEqn,yEqn,t,x) + elseif curveType == "END_POINTS_LINE" + xStart = realArrayForKeyFromDictionary("xStart",crvDict) + xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) + x = zeros(Float64,3) + endPointsLineCurvePoint(xStart,xEnd,t,x) + elseif curveType == "CIRCULAR_ARC" + center = realArrayForKeyFromDictionary("center",crvDict) + radius = realForKeyFromDictionary("radius",crvDict) + startAngle = realForKeyFromDictionary("start angle",crvDict) + endAngle = realForKeyFromDictionary("end angle",crvDict) + units = crvDict["units"] + x = zeros(Float64,3) + arcCurvePoint(center,radius,startAngle,endAngle,units,t,x) + elseif curveType == "SPLINE_CURVE" + nKnots = intForKeyFromDictionary("nKnots",crvDict) + splineData = crvDict["SPLINE_DATA"] + x = zeros(Float64,3) + splineCurvePoint(nKnots,splineData,t,x) + else + + end + return x +end + +function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}) + xFirst = curvePoint(firstCurve,1.0) + xSecond = curvePoint(secondCurve,0.0) + if maximum(abs.(xFirst - xSecond)) < 100*eps(Float64) + return true + else + return false + end +end diff --git a/HQMTool/Source/Curves/Spline.jl b/HQMTool/Source/Curves/Spline.jl new file mode 100644 index 00000000..6d34f47a --- /dev/null +++ b/HQMTool/Source/Curves/Spline.jl @@ -0,0 +1,131 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +mutable struct Spline + N::Int + x::Array{Float64} + y::Array{Float64} + b::Array{Float64} + c::Array{Float64} + d::Array{Float64} + last::Int +end + +function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) + b = zeros(Float64,N) + c = zeros(Float64,N) + d = zeros(Float64,N) + + Nm1 = N - 1 +# +# Set up tri-diagonal system +# + d[1] = x[2] - x[1] + c[2] = (y[2] - y[1])/d[1] + for i = 2:Nm1 + d[i] = x[i+1] - x[i] + b[i] = 2.0*(d[i-1] + d[i]) + c[i+1] = (y[i+1] - y[i])/d[i] + c[i] = c[i+1] - c[i] + end +# +# end conditions +# + b[1] = -d[1] + b[N] = -d[N-1] + c[1] = c[3]/(x[4] - x[2]) - c[2]/(x[3] - x[1]) + c[N] = c[N-1]/(x[N] - x[N-2]) - c[N-2]/(x[N-1] - x[N-3]) + c[1] = c[1]*d[1]^2/(x[4] - x[1]) + c[N] = -c[N]*d[N-1]^2/(x[N] - x[N-3]) +# +# Forward elimination +# + t = 0.0 + for i = 2:N + t = d[i-1]/b[i-1] + b[i] = b[i] - t*d[i-1] + c[i] = c[i] - t*c[i-1] + end +# +# Back substitution +# + c[N] = c[N]/b[N] + for ib = 1:Nm1 + i = N - ib + c[i] = (c[i] - d[i]*c[i+1])/b[i] + end +# +# Compute polynomial coefficients +# + b[N] = (y[N] - y[Nm1])/d[Nm1] + d[Nm1]*(c[Nm1] + 2.0*c[N]) + for i = 1: Nm1 + b[i] = (y[i+1] - y[i])/d[i] - d[i]*(c[i+1] + 2.0*c[i]) + d[i] = (c[i+1] - c[i])/d[i] + c[i] = 3.0*c[i] + end + c[N] = 3.0*c[N] + d[N] = d[N-1] + + spl = Spline(N,x,y,b,c,d,1) + return spl +end + +function evalSpline(spl::Spline, u::Float64) + N = spl.N + s = 0.0 + i = spl.last + + if i >= N + i = 1 + end + + if spl.x[i] < u <= spl.x[i+1] + dx = u - spl.x[i] + s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) + spl.last = i + return s + end + + i = 1 + j = N+1 + + for ii = 1:N + k = div(i+j,2) + if u < spl.x[k] + j = k + end + if u >= spl.x[k] + i = k + end + if j <= i+1 + break + end + end + dx = u - spl.x[i] + s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) + spl.last = i + return s +end \ No newline at end of file diff --git a/HQMTool/Source/Mesh/Meshing.jl b/HQMTool/Source/Mesh/Meshing.jl new file mode 100644 index 00000000..15739d62 --- /dev/null +++ b/HQMTool/Source/Mesh/Meshing.jl @@ -0,0 +1,53 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using HOHQMesh + +function generateMesh(proj::Project) +# +# Check to be sure background grid has been created (everhtying else is defaults) +# + controlDict = getControlDict(proj) + if !haskey(controlDict,"BACKGROUND_GRID") + println("A background grid is needed before meshing. Add one and try again.") + return nothing + end + path = mkpath(proj.projectDirectory) + saveProject(proj) + fileName = joinpath(proj.projectDirectory,proj.name)*".control" + mesherOutput = generate_mesh(fileName, output_directory = proj.projectDirectory) + println(mesherOutput) + postNotificationWithName(proj,"MESH_WAS_GENERATED_NOTIFICATION",(nothing,)) + return nothing +end + +function removeMesh!(proj::Project) + meshFile = getMeshFileName(proj) + rm(meshFile) + proj.xMesh = Float64[] + proj.yMesh = Float64[] + postNotificationWithName(proj,"MESH_WAS_DELETED_NOTIFICATION",(nothing,)) +end diff --git a/HQMTool/Source/Misc/DictionaryOperations.jl b/HQMTool/Source/Misc/DictionaryOperations.jl new file mode 100644 index 00000000..96bbc960 --- /dev/null +++ b/HQMTool/Source/Misc/DictionaryOperations.jl @@ -0,0 +1,89 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +#= + Some useful getters for a dictionary +=# +arrayRegex = r"(?<=\[).+?(?=\])" + +function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return parse(Float64,v) +end + +function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return parse(Int64,v) +end + +function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return v +end + +function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + values = match(arrayRegex,v) + s = split(values.match,",") + array = [parse(Float64,s[1]),parse(Float64,s[2]),parse(Float64,s[3])] + return array +end + +function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + values = match(arrayRegex,v) + s = split(values.match,",") + array = [parse(Int,s[1]),parse(Int,s[2]),parse(Int,s[3])] + return array +end + +function keyAndValueFromString(s) + indxOfEqual = findfirst("=",s) + if indxOfEqual === nothing + return nothing + end + key = strip(s[1:indxOfEqual.start-1],[' ','\t']) + value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) + return (key,value) +end + +function showDescription(d::Dict, pre=1) + todo = Vector{Tuple}() + for (k,v) in d + if typeof(v) <: Dict + push!(todo, (k,v)) + else + println(join(fill(" ", pre)) * "$(repr(k)) => $(repr(v))") + end + end + + for (k,d) in todo + s = "$(repr(k)) => " + println(join(fill(" ", pre)) * s) + showDescription(d, pre+1+length(s)) + end + nothing +end diff --git a/HQMTool/Source/Misc/NotificationCenter.jl b/HQMTool/Source/Misc/NotificationCenter.jl new file mode 100644 index 00000000..b2ae9586 --- /dev/null +++ b/HQMTool/Source/Misc/NotificationCenter.jl @@ -0,0 +1,107 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +struct HQMNotification + sender ::Any # Who sent the notification + userInfo ::Tuple # Any necessary data needed +end + +struct HQMNotificationObject + observer::Any + fcn ::Any +end + +HQMNotificationCenter = Dict{String,Vector{HQMNotificationObject}}() +HQMNotificationsON = true + +""" + addObserver(observer::Any, note::String, fnction::Any) + +fnction is the function to be executed (called) when a +notification of name `note` is given. + +The function called upon notification must have the signature +fnction(observer, sender, args...) +""" +function addObserver(observer::Any, note::String, fnction::Any) + + noteObj = HQMNotificationObject(observer,fnction) + if !haskey(HQMNotificationCenter,note) + HQMNotificationCenter[note] = HQMNotificationObject[] + end + push!(HQMNotificationCenter[note],noteObj) +end +""" + unRegisterForNotification(observer::Any, note::String) + +Remove the observer from being notified by the notification `note` +""" +function unRegisterForNotification(observer::Any, note::String) + if haskey(HQMNotificationCenter,note) + global observers = HQMNotificationCenter[note] + + for i = 1:length(observers) + global noteObj = observers[i] + noteObserver = noteObj.observer + if noteObserver === observer + deleteat!(observers,i) + break + end + end + if isempty(observers) + delete!(HQMNotificationCenter,note) + end + end +end +""" + postNotificationWithName(sender::Any, name::String, userInfo::Tuple) + +Executes the function associated with the observer for the notification `note` +""" +function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) + if haskey(HQMNotificationCenter,note) && HQMNotificationsON + global observers = HQMNotificationCenter[note] + + for i = 1:length(observers) + global noteObj = observers[i] + f = noteObj.fcn + observer = noteObj.observer + if isnothing(userInfo[1]) + f(observer,sender) + else + f(observer,sender,userInfo...) + end + end + end +end + +function enableNotifications() + global HQMNotificationsON = true +end + +function disableNotifications() + global HQMNotificationsON = false +end diff --git a/HQMTool/Source/Model/Geometry.jl b/HQMTool/Source/Model/Geometry.jl new file mode 100644 index 00000000..71a99954 --- /dev/null +++ b/HQMTool/Source/Model/Geometry.jl @@ -0,0 +1,93 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +const TOP = 1; const LEFT = 2; const BOTTOM = 3; const RIGHT = 4 + +""" +curveBounds(crvPoints::Array{Float64,2}) + +Find the bounds of a single curve, discretized as an array +""" +function curveBounds(crvPoints::Array{Float64,2}) + + s = size(crvPoints) + top = -Inf64 + left = Inf64 + bottom = Inf64 + right = -Inf64 + + for i = 1:s[1] + right = max(right,crvPoints[i,1]) + left = min(left,crvPoints[i,1]) + top = max(top,crvPoints[i,2]) + bottom = min(bottom,crvPoints[i,2]) + end + + bounds = zeros(Float64,4) + bounds[TOP] = top + bounds[LEFT] = left + bounds[BOTTOM] = bottom + bounds[RIGHT] = right + + return bounds +end + +function chainBounds(chain::Array{Any}) + bounds = emptyBounds() + for crv in chain + crvBounds = curveBounds(crv) + bounds = bboxUnion(bounds,crvBounds) + end + return bounds +end + +""" + bboxUnion(box1::Array{Float64}, box2::Array{Float64}) + +Returns the union of two bounding boxes +""" +function bboxUnion(box1::Array{Float64}, box2::Array{Float64}) + union = zeros(Float64,4) + union[TOP] = max(box1[TOP] ,box2[TOP]) + union[LEFT] = min(box1[LEFT] ,box2[LEFT]) + union[BOTTOM] = min(box1[BOTTOM],box2[BOTTOM]) + union[RIGHT] = max(box1[RIGHT] ,box2[RIGHT]) + + return union +end +""" + +Returns an array that will always be ignored when unioned with +another bounding box. +""" +function emptyBounds() + emptee = zeros(Float64,4) + emptee[TOP] = -Inf64 + emptee[LEFT] = Inf64 + emptee[BOTTOM] = Inf64 + emptee[RIGHT] = -Inf64 + return emptee +end diff --git a/HQMTool/Source/Project/BackgroundGridAPI.jl b/HQMTool/Source/Project/BackgroundGridAPI.jl new file mode 100644 index 00000000..687038af --- /dev/null +++ b/HQMTool/Source/Project/BackgroundGridAPI.jl @@ -0,0 +1,265 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addBackgroundGrid(proj::Project, bgSize::Array{Float64}) + +Add the background grid block with the grid size to be a 3-vector. Use this when there +is an outer boundary defined in the model. +""" +function addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + disableUndo() + disableNotifications() + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + setBackgroundGridSize!(proj, bgSize, "background grid size") + enableUndo() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + enableNotifications() + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) + +Add the background grid block with bounding box = [TOP, LEFT, BOTTOM, RIGHT] +and the number of intervals in each diredction. Use this when there +is _no_ outer boundary defined in the model. +""" +function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + disableUndo() + disableNotifications() + proj.bounds = box + proj.userBounds = deepcopy(box) + + dx = zeros(Float64,3) + dx[1] = (box[RIGHT] - box[LEFT])/N[1] + dx[2] = (box[TOP] - box[BOTTOM])/N[2] + + setBackgroundGridSize!(proj, dx, "dx") + setBackgroundGridLowerLeft!(proj,[box[LEFT], box[BOTTOM], 0.0]) + setBackgroundGridSteps!(proj,N) + enableUndo() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + enableNotifications() + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + +Add the background grid block using the left corner, x0, the +grid size dx, and the number of intervals in each direction. Use this when there +is _no_ outer boundary defined in the model. This version mimics HOHQMesh's +backgroundGrid block, but the version + + addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) + +is a lot easier to use. + +TODO: Change HOHQMesh and delete this way to specify the domain and use the bounding box one instead. + +""" +function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + disableUndo() + disableNotifications() + setBackgroundGridSize!(proj, dx, "dx") + setBackgroundGridLowerLeft!(proj,x0) + setBackgroundGridSteps!(proj,N) + proj.userBounds[TOP] = x0[2] + N*dx[2] + proj.userBounds[LEFT] = x0[1] + proj.userBounds[BOTTOM] = x0[2] + proj.userBounds[RIGHT] = x0[1] + N*dx[1] + enableUndo() + enableNotifications() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + removeBackgroundGrid!(proj::Project) + +Remove the background grid block from the project. +""" +function removeBackgroundGrid!(proj::Project) + cDict = getControlDict(proj) + registerWithUndoManager(proj,addBackgroundGrid!,(cDict,),"Delete Background Grid") + delete!(cDict,"RUN_PARAMETERS") + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + setBackgroundGridSpacing!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + +User facing function +""" +function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + newSize = [dx,dy] + if haskey(bgDict,"dx") + oldSpacing = realArrayForKeyFromDictionary("dx", bgDict) + setBackgroundGridSize!(proj, newSize, "dx") + # With the "corner+intervals" setting of the outer boundary deprecated, keep + # the original bounds fixed. + x0 = realArrayForKeyFromDictionary("x0",bgDict) + Nx = round(Int,(proj.userBounds[RIGHT] - proj.userBounds[LEFT]) /dx[1]) + Ny = round(Int,(proj.userBounds[TOP] - proj.userBounds[BOTTOM])/dx[2]) + N = [Nx,Ny,0] + disableNotifications() + setBackgroundGridSteps!(proj,N) + enableNotifications() + else + oldSpacing = realArrayForKeyFromDictionary("background grid size", bgDict) + setBackgroundGridSize!(proj, newSize, "background grid size") + end + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + registerWithUndoManager(proj,setBackgroundGridSize!, + (oldSpacing[1],oldSpacing[2],0.0),"Set Background Grid Spacing") + return nothing + end +""" + getBackgroundGridSize(proj::Project) + +Returns the background grid size array. +""" +function getBackgroundGridSize(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"dx") + return realArrayForKeyFromDictionary("dx",bgDict) + elseif haskey(bgDict,"background grid size") + return realArrayForKeyFromDictionary("background grid size",bgDict) + else + return nothing + end +end +""" + function getBackgroundGridLowerLeft(proj::Project) + +Returns the [x,y] of the lower left point of thebackground grid. +""" +function getBackgroundGridLowerLeft(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"x0") + return realArrayForKeyFromDictionary("x0",bgDict) + else + return nothing + end +end +""" + function getBackgroundGridLowerLeft(proj::Project) + +Returns the [x,y,z] of the lower left point of thebackground grid. +""" +function getBackgroundGridSteps(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"N") + return realIntForKeyFromDictionary("N",bgDict) + else + return nothing + end +end +""" + setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + +Set the lower left location of the background grid for problems that have no +outer boundary. +""" +function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,"x0") + oldLowerLeft = realArrayForKeyFromDictionary("x0",bgDict) + registerWithUndoManager(proj,setBackgroundGridLowerLeft!, + (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") + end + + x0Str = @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) + bgDict["x0"] = x0Str + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end +""" +setBackgroundGridSteps!(proj::Project, N::Array{Int}) + +Set how many steps of size setBackgroundGridSpacing in each direction the background grid extends from the +lower left. +""" +function setBackgroundGridSteps!(proj::Project, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,"N") + oldN = intArrayForKeyFromDictionary("N",bgDict) + registerWithUndoManager(proj,setBackgroundGridSteps!, + (oldN[1],oldN[2],oldN[3]),"Set Background Steps") + end + + NStr = @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) + bgDict["N"] = NStr + + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end +""" +setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) +""" +function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + setBackgroundGridSize!(proj, dx[1], dx[2], key) + return nothing +end +""" +setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) +""" +function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,key) + oldDx = realArrayForKeyFromDictionary(key,bgDict) + registerWithUndoManager(proj,setBackgroundGridSize!, + (oldDx[1],oldDx[2],oldDx[3]),"Set Background Size") + end + + dxStr = @sprintf("[%f,%f,%f]", dx, dy, 0.0) + bgDict[key] = dxStr + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) + +Used only for undo/redo. +""" +function addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) + controlDict = getControlDict(proj) + controlDict["BACKGROUND_GRID"] = dict + return nothing +end + diff --git a/HQMTool/Source/Project/ControlInputAPI.jl b/HQMTool/Source/Project/ControlInputAPI.jl new file mode 100644 index 00000000..33ec96e4 --- /dev/null +++ b/HQMTool/Source/Project/ControlInputAPI.jl @@ -0,0 +1,60 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +function getControlDict(proj::Project) + if haskey(proj.projectDictionary,"CONTROL_INPUT") + return proj.projectDictionary["CONTROL_INPUT"] + else + controlDict = Dict{String,Any}() + proj.projectDictionary["CONTROL_INPUT"] = controlDict + controlDict["TYPE"] = "CONTROL_INPUT" + return controlDict + end +end + +function getDictInControlDictNamed(proj::Project,name::String) + controlDict = getControlDict(proj) + + if haskey(controlDict,name) + return controlDict[name] + else + d = Dict{String,Any}() + controlDict[name] = d + d["TYPE"] = name + return d + end +end + +function getListInControlDictNamed(proj::Project,name::String) + dict = getDictInControlDictNamed(proj::Project,name::String) + if haskey(dict,"LIST") + return dict["LIST"] + else + lst = [] + dict["LIST"] = lst + return lst + end +end diff --git a/HQMTool/Source/Project/CurvesAPI.jl b/HQMTool/Source/Project/CurvesAPI.jl new file mode 100644 index 00000000..090e56d5 --- /dev/null +++ b/HQMTool/Source/Project/CurvesAPI.jl @@ -0,0 +1,450 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + +Creates and returns a new parametricEquationCurve in the form of a Dictionary +""" +function newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + + crv = Dict{String,Any}() + crv["TYPE"] = "PARAMETRIC_EQUATION_CURVE" + disableNotifications() + disableUndo() + setCurveName!(crv,name) + setXEqn!(crv,xEqn) + setYEqn!(crv,yEqn) + setZEqn!(crv,zEqn) + enableUndo() + enableNotifications() + return crv +end +""" + newEndPointsLineCurve(name::String, xStart::Array{Float64},xEnd::Array[Float64]) + +Creates and returns a new curve defined by its end points in the form of a Dictionary +""" +function newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + crv = Dict{String,Any}() + crv["TYPE"] = "END_POINTS_LINE" + disableNotifications() + disableUndo() + setCurveName!(crv,name) + setStartPoint!(crv,xStart) + setEndPoint!(crv,xEnd) + enableNotifications() + enableUndo() + return crv +end +""" + newCircularArcCurve(name::String, center::Array{Float64}, + startAngle::Float64, endAngle::Float64, + units::String) + +Creates and returns a new circular arc curve in the form of a Dictionary +""" +function newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String = "degrees") + + arc = Dict{String,Any}() + arc["TYPE"] = "CIRCULAR_ARC" + disableNotifications() + disableUndo() + setCurveName!(arc,name) + setArcUnits!(arc,units) + setArcCenter!(arc,center) + setArcStartAngle!(arc,startAngle) + setArcEndAngle!(arc,endAngle) + setArcRadius!(arc,radius) + enableNotifications() + enableUndo() + return arc +end +""" + newSplineCurve(name::String, nKnots::Int, data::Array{Float64,4}) + +Returns a spline curve given the number of knots and the array of knots. +""" +function newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + spline = Dict{String,Any}() + spline["TYPE"] = "SPLINE_CURVE" + disableNotifications() + disableUndo() + setCurveName!(spline,name) + setSplineNKnots!(spline,nKnots) + setSplinePoints!(spline,data) + enableNotifications() + enableUndo() + return spline +end +""" + newSplineCurve(name::String, dataFile::String) + +Returns a spline curve given a data file that contains the number of knots +on the first line, and the spline data following that. +""" +function newSplineCurve(name::String, dataFile::String) + + spline = Dict{String,Any}() + open(dataFile,"r") do f + nKnots = parse(Int,readline(f)) + splineDataArray = zeros(Float64,nKnots,4) + for i = 1:nKnots + currentLine = split(readline(f)) + for j = 1:4 + splineDataArray[i,j] = parse(Float64,currentLine[j]) + end + end + spline = newSplineCurve(name, nKnots, splineDataArray) + end + return spline +end +""" + duplicateCurve(crv::Dict{String,Any}, newName::String) + +Duplicate the given curve giving it the new name. +""" +function duplicateCurve(crv::Dict{String,Any}, newName::String) + disableNotifications() + disableUndo() + + duplicate = deepcopy(crv) + setCurveName!(duplicate,newName) + + enableNotifications() + enableUndo() + return duplicate +end +""" + setCurveName!(curveDict, name) + +Set the name of the curve represented by curveDict. +""" +function setCurveName!(crv::Dict{String,Any}, name::String) + if haskey(crv,"name") + oldName = crv["name"] + registerWithUndoManager(crv,setCurveName!, (oldName,), "Set Curve Name") + postNotificationWithName(crv,"CURVE_DID_CHANGE_NAME_NOTIFICATION",(oldName,)) + end + crv["name"] = name +end +""" + getCurveName(crv::Dict{String,Any}) +""" +function getCurveName(crv::Dict{String,Any}) + return crv["name"] +end +""" + getCurveType(crv::Dic{String,Any}) + + Get the type of the curve, `END_POINTSLINE_CURVE`, `PARAMETRIC_EQUATION_CURVE`, + `SPLINE_CURVE`, or `CIRCULAR_ARC` as a string. +""" +function getCurveType(crv::Dict{String,Any}) + return crv["TYPE"] +end +""" + setXEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the x-equation. +""" +function setXEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"xEqn") + oldEqn = crv["xEqn"] + registerWithUndoManager(crv,setXEqn!, (eqn,), "Set X Equation") + end + crv["xEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getXEqn(crv::Dict{String,Any}) +""" +function getXEqn(crv::Dict{String,Any}) + if(haskey(crv,"xEqn")) + return crv["xEqn"] + end + return nothing +end +""" + setYEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the y-equation. +""" +function setYEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"yEqn") + oldEqn = crv["yEqn"] + registerWithUndoManager(crv,setYEqn!, (eqn,), "Set Y Equation") + end + crv["yEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getYEqn(crv::Dict{String,Any}) +""" +function getYEqn(crv::Dict{String,Any}) + if(haskey(crv,"yEqn")) + return crv["yEqn"] + end + return nothing +end +""" + setZEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the zEqn-equation. +""" +function setZEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"zEqn") + oldEqn = crv["zEqn"] + registerWithUndoManager(crv,setZEqn!, (eqn,), "Set Z Equation") + end + crv["zEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getZEqn(crv::Dict{String,Any}) +""" +function getZEqn(crv::Dict{String,Any}) + if(haskey(crv,"zEqn")) + return crv["zEqn"] + end + return nothing +end +""" + setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the start point for a line curve. +""" +function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + key = "xStart" + if haskey(crv,key) + oldPt = crv[key] + registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") + end + crv[key] = pStr + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) + crv["xStart"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getStartPoint(crv::Dict{String,Any}, point::Array{Float64}) + +Get the start point for a line curve as an array +""" +function getStartPoint(crv::Dict{String,Any}) + return realArrayForKeyFromDictionary("xStart",crv) +end +""" + setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the end point for a line curve. +""" +function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + key = "xEnd" + if haskey(crv,key) + oldPt = crv[key] + registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") + end + crv[key] = pStr + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) + crv["xEnd"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getEndPoint(crv::Dict{String,Any}, point::Array{Float64}) + +Get the end point for a line curve as an array. +""" +function getEndPoint(crv::Dict{String,Any}) + return realArrayForKeyFromDictionary("xEnd",crv) +end +""" + setArcUnits(crv::Dict{String,Any}, units::String) + +Set the units for the start and end angles of a circular arc curve. +""" +function setArcUnits!(arc::Dict{String,Any}, units::String) + if units == "degrees" || units == "radians" + key = "units" + if haskey(arc,key) + oldUnits = arc[key] + registerWithUndoManager(arc,setArcUnits!, (oldUnits,), "Set Arc Units") + end + arc[key] = units + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) + else + println("Units must either be `degrees` or `radians`. Try setting `units` again.") + end +end +""" + getArcUnits(crv::Dict{String,Any}, units::String) + +Get the units for the start and end angles of a circular arc curve. +""" +function getArcUnits!(arc::Dict{String,Any}) + return arc["units"] +end +""" + setArcCenter!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the center of a circular arc. +""" +function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + key = "center" + if haskey(arc,key) + oldVal = arc[key] + registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") + end + + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + arc[key] = pStr + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) + arc["center"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcCenter(crv::Dict{String,Any}, point::Array{Float64}) + +Get the center of a circular arc as an array +""" +function getArcCenter(arc::Dict{String,Any}) + return realArrayForKeyFromDictionary("center",arc) +end +""" + setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + + """ +function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + key = "start angle" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcStartAngle!, (oldVal,), "Set Arc Start Angle") + end + arc[key] = string(angle) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcStartAngle(arc::Dict{String,Any}, angle::Float64) + + """ +function getArcStartAngle(arc::Dict{String,Any}) + return parse(Float64,arc["start angle"]) +end +""" + setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + + """ +function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + key = "end angle" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcEndAngle!, (oldVal,), "Set Arc Start Angle") + end + arc[key] = string(angle) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcEndAngle(arc::Dict{String,Any}, angle::Float64) + + """ +function getArcEndAngle(arc::Dict{String,Any}) + return parse(Float64,arc["end angle"]) +end +""" + setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + """ +function setArcRadius!(arc::Dict{String,Any}, radius::Float64) + key = "radius" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcRadius!, (oldVal,), "Set Arc Radius") + end + arc[key] = string(radius) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcRadius(arc::Dict{String,Any}, radius::Float64) + +""" +function getArcRadius(arc::Dict{String,Any}) + return parse(Float64,arc["radius"]) +end +""" + setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) +""" +function setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) + key = "nKnots" + if haskey(spline,key) + oldVal = parse(Int,spline[key]) + registerWithUndoManager(spline,setSplineNKnots!, (oldVal,), "Set Spline Knots") + end + spline["nKnots"] = string(nKnots) + postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getSplineNKnots(spline::Dict{String,Any}) +""" +function getSplineNKnots(spline::Dict{String,Any}) + return parse(Int,spline["nKnots"]) +end +""" + setSplinePoints!(spline::Dict{String,Any},points::Array{Float64,4}) +""" +function setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) + key = "SPLINE_DATA" + if haskey(spline,key) + registerWithUndoManager(spline,setSplinePoints!, (spline["SPLINE_DATA"],), "Set Spline Points") + end + spline["SPLINE_DATA"] = points + postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getSplinePoints(spline::Dict{String,Any}) +""" +function getSplinePoints(spline::Dict{String,Any}) + return spline["SPLINE_DATA"] +end diff --git a/HQMTool/Source/Project/Generics.jl b/HQMTool/Source/Project/Generics.jl new file mode 100644 index 00000000..c8976072 --- /dev/null +++ b/HQMTool/Source/Project/Generics.jl @@ -0,0 +1,164 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +# +# Creating curves +# +""" + new(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + +Create a new parametric equation curve. +""" +function new(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + return newParametricEquationCurve(name, xEqn, yEqn, zEqn) +end + +""" + new(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + +Create a new line defined by its end points. +""" +function new(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + return newEndPointsLineCurve(name, xStart, xEnd) +end + +""" + new(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) + +Create a new circular arc. +""" +function new(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String = "degrees") + return newCircularArcCurve(name,center,radius,startAngle,endAngle,units) +end + +""" + new(name::String, dataFile::String) + +Create a spline curve from the contents of a data file. +""" +function new(name::String, dataFile::String) + return newSplineCurve(name, dataFile) +end + +""" + new(name::String, nKnots::Int, data::Matrix{Float64}) + +Create a spline curve from an array of knots +""" +function new(name::String, nKnots::Int, data::Matrix{Float64}) + return newSplineCurve(name, nKnots, data) +end +# +# Adding curves to a model +# +""" + add!(proj::Project, obj::Dict{String,Any}) + +Add a curve to the outer boundary or a refinement reion to +the project +""" +function add!(proj::Project, obj::Dict{String,Any}) + if obj["TYPE"] == "REFINEMENT_CENTER" || obj["TYPE"] == "REFINEMENT_LINE" + addRefinementRegion!(proj, obj) + else + addCurveToOuterBoundary!(proj, obj) + end +end + +""" + add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + +Add a curve to the inner boundary named `boundaryName`. +""" +function add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + addCurveToInnerBoundary!(proj, crv, boundaryName) +end + +""" +get(proj::Project, curveName::String) + +Get the curve with name `curveName` from the outer boundary. +""" +function get(proj::Project, curveName::String) + return getOuterBoundaryCurveWithName(proj, curveName) +end + +""" + get(proj::Project, curveName::String, boundaryName::String) + +Get the curve named `curveName` from the inner boundary named `boundaryName` +""" +function get(proj::Project, curveName::String, boundaryName::String) + return getInnerBoundaryCurve(proj, curveName, boundaryName) +end + +""" + getInnerBoundary(proj::Project, name::String) + +Get the chain of curves from the inner boundary with name `name`. +""" +function getInnerBoundary(proj::Project, name::String) + return getInnerBoundaryChainWithName(proj, name) +end + +""" + remove!(proj::Project, curveName::String) + +Delete the curve named curveName from the outer boundary +""" +function remove!(proj::Project, curveName::String) + removeOuterBoundaryCurveWithName!(proj, curveName) +end + +""" + remove!(proj::Project, curveName::String, innerBoundaryName::String) + +Delete the curve named curveName from the inner boundary named innerBoundaryName +""" +function remove!(proj::Project, curveName::String, innerBoundaryName::String) + removeInnerBoundaryCurve!(proj, curveName, innerBoundaryName) +end + diff --git a/HQMTool/Source/Project/ModelAPI.jl b/HQMTool/Source/Project/ModelAPI.jl new file mode 100644 index 00000000..336f70ae --- /dev/null +++ b/HQMTool/Source/Project/ModelAPI.jl @@ -0,0 +1,427 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +include("../Model/Geometry.jl") + +# +# -------------------------------------------------------------------------------------- +# +""" + addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + +Add a curve to the outer boundary. The curves must be added in order counter-clockwise +""" +function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + chain = getOuterBoundaryChainList(proj) +# +# Check if the new curve meets the last one added +# + if !isempty(chain) + lastCurve = last(chain) + if !curvesMeet(lastCurve,crv) + lastName = getCurveName(lastCurve) + newName = getCurveName(crv) + println("the curve $lastName does not meet the previous curve, $newName. Try again.") + return + end + end +# +# Checks out, add to model +# + push!(chain,crv) + crvPoints = curvePoints(crv,defaultPlotPts) + push!(proj.outerBndryPoints, crvPoints) + proj.backgroundGridShouldUpdate = true + + push!(proj.outerBndryNames,crv["name"]) + + enableUndo() + registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") + enableNotifications() + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + removeOuterBoundaryCurveWithName!(proj::Project, name::String) + +Remove the named curve in the outer boundary +""" +function removeOuterBoundaryCurveWithName!(proj::Project, name::String) + lst = getOuterBoundaryChainList(proj) + indx = getChainIndex(lst,name) + if indx > 0 + removeOuterBoundaryCurveAtIndex(proj,indx) # posts undo/notification + proj.backgroundGridShouldUpdate = true + end +end +""" + getOuterBoundaryCurveWithName(proj::Project, name::String) +""" +function getOuterBoundaryCurveWithName(proj::Project, name::String) + lst = getOuterBoundaryChainList(proj) + for crv in lst + if crv["name"] == name + return crv + end + end +end +""" + insertOuterBoundaryCurveAtIndex(proj::Project, crv::Dict{String,Any}, indx::Int) + +Insert a curve at the specified index. +""" +function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) + lst = getOuterBoundaryChainList(proj) + insert!(lst,indx,crv) + insert!(proj.outerBndryPoints,indx,curvePoints(crv,defaultPlotPts)) + insert!(proj.outerBndryNames,indx,crv["name"]) + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end + +function removeOuterBoundaryCurveAtIndex(proj::Project, indx::Int) + lst = getOuterBoundaryChainList(proj) + crv = lst[indx] + deleteat!(lst,indx) + deleteat!(proj.outerBndryNames,indx) + deleteat!(proj.outerBndryPoints,indx) + proj.backgroundGridShouldUpdate = true + enableNotifications() + enableUndo() + registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Add Curve") + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + addOuterBoundary!(proj::Project) + +Add an empty outer boundary to the project. There can be only one. +""" +function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) + model = getModelDict(proj) + model["OUTER_BOUNDARY"] = outerBoundary + registerWithUndoManager(proj,removeOuterboundary!, (nothing,), "Add Outer Boundary") +end +""" + removeOuterboundary!(proj::Project) + +Remove the outer boundary curve if it exists. +""" +function removeOuterboundary!(proj::Project) + modelDict = getModelDict(proj) + if haskey(modelDict,"OUTER_BOUNDARY") + ob = modelDict["OUTER_BOUNDARY"] + enableUndo() + registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") + delete!(modelDict,"OUTER_BOUNDARY") + proj.outerBndryPoints = Any[] + proj.outerBndryNames = String[] + proj.backgroundGridShouldUpdate = true + enableNotifications() + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) + end +end + +function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) + modelDict = getModelDict(proj) + modelDict["OUTER_BOUNDARY"] = obDict +end +# +# -------------------------------------------------------------------------------------- +# +""" + getOuterBoundary(proj::Project) + +Get the array of outer boundary curves. +""" +function getOuterBoundaryChainList(proj::Project) + outerBndryDict = getDictInModelDictNamed(proj,"OUTER_BOUNDARY") + if haskey(outerBndryDict,"LIST") + lst = outerBndryDict["LIST"] + return lst + else + lst = Dict{String,Any}[] + outerBndryDict["LIST"] = lst + return lst + end +end +# +# -------------------------------------------------------------------------------------- +# INNER BOUNDARY FUNCTIONS +# -------------------------------------------------------------------------------------- +# +""" + addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + +Add a curve to the inner boundary with name `boundaryName`. If an inner boundary of that name +does not exist, one is created. +""" +function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + curveList = chain["LIST"] +# +# Check if the new curve meets the last one added +# + if !isempty(curveList) + lastCurve = last(curveList) + if !curvesMeet(lastCurve,crv) + lastName = getCurveName(lastCurve) + newName = getCurveName(crv) + println("the curve $lastName does not meet the previous curve, $newName. Try again.") + return + end + end +# +# Checks out, add to model +# + push!(curveList,crv) + + if i > length(proj.innerBoundaryPoints) # New inner boundary chain + a = [] + push!(a,curvePoints(crv,defaultPlotPts)) + push!(proj.innerBoundaryPoints,a) + else + a = proj.innerBoundaryPoints[i] + push!(a,curvePoints(crv,defaultPlotPts)) + end + push!(proj.innerBoundaryNames[i],crv["name"]) + proj.backgroundGridShouldUpdate = true + registerWithUndoManager(proj,removeInnerBoundaryCurve!, + (crv["name"],boundaryName), + "Add Inner Boundary Curve") + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + removeInnerBoundaryCurve!(proj::Project, name::String) + +Remove the named curve in the outer boundary +""" +function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + i, chain = getInnerBoundaryChainWithName(proj,chainName) + lst = chain["LIST"] + if isempty(lst) + println("No curve ", name, " in boundary ", chainName) #TODO Replace with error() + return + end + indx = getChainIndex(lst,name) + removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) +end + +function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, + indx::Int, boundaryName::String) + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + lst = chain["LIST"] + insert!(lst,indx,crv) + innerBoundaryPoints = proj.innerBoundaryPoints[i] + insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) + insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end + +function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) + i, chain = getInnerBoundaryChainWithName(proj,chainName) + lst = chain["LIST"] + if indx > 0 + crv = lst[indx] + deleteat!(lst,indx) + deleteat!(proj.innerBoundaryNames[i],indx) + deleteat!(proj.innerBoundaryPoints[i],indx) + registerWithUndoManager(proj,insertInnerBoundaryCurveAtIndex!, + (crv,indx,chainName), + "Remove Inner Boundary Curve") + if isempty(lst) + ibChains = getAllInnerBoundaries(proj) + deleteat!(ibChains,i) + deleteat!(proj.innerBoundaryChainNames,i) + deleteat!(proj.innerBoundaryPoints,i) + end + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) + end +end +""" + removeInnerBoundary!(proj::Project, chainName::String) + +Remove an entire inner boundary +""" +function removeInnerBoundary!(proj::Project, chainName::String) + i,crv = getInnerBoundaryChainWithName(p,chainName) + deleteat!(proj.innerBoundaryChainNames,i) + deleteat!(proj.innerBoundaryPoints,i) + ibChains = getAllInnerBoundaries(proj) + deleteat!(ibChains,i) +end +# +# -------------------------------------------------------------------------------------- +# +""" + addInnerBoundaryWithName!(proj::Project,name::String) + +Create a new empty inner boundary with the given name. +""" +function addInnerBoundaryWithName!(proj::Project,name::String) +# +# Create a new chain +# + bndryChain = Dict{String,Any}() + bndryChain["name"] = name + bndryChain["TYPE"] = "CHAIN" + bndryCurves = Dict{String,Any}[] + bndryChain["LIST"] = bndryCurves + + innerBoundariesList = getAllInnerBoundaries(proj) + push!(innerBoundariesList,bndryChain) +# +# Prepare for plotting +# + push!(proj.innerBoundaryChainNames,name) + componentNames = String[] + push!(proj.innerBoundaryNames,componentNames) + + return bndryChain +end +# +#---------------------------------------------------------------------------------------- +# +function getChainIndex(chain::Vector{Dict{String, Any}},name) + for (i,dict) in enumerate(chain) + if dict["name"] == name + return i + end + end + return 0 +end +""" + getAllInnerBoundaries(proj::Project) + +Returns an array of the inner boundaries +""" +# +# -------------------------------------------------------------------------------------- +# +function getAllInnerBoundaries(proj::Project) + innerBndryDict = getDictInModelDictNamed(proj,"INNER_BOUNDARIES") + if haskey(innerBndryDict,"LIST") + lst = innerBndryDict["LIST"] + return lst + else + lst = [] + innerBndryDict["LIST"] = lst + return lst + end + return nothing +end +# +# -------------------------------------------------------------------------------------- +# +""" + getInnerBoundaryWithName(proj::Project, name::String) + +Get the inner boundary CHAIN with the given name. If one does not exist, it +is created. +""" +function getInnerBoundaryChainWithName(proj::Project, name::String) + lst = getAllInnerBoundaries(proj::Project) + # + # See if there is an inner boundary with that name + # + l = length(lst) + i = 1 + if l > 0 + for chain in lst + bCurveName = chain["name"] + if bCurveName == name + return i, chain + i = i + 1 + end + end + end + # + # If not, create one + # + chain = addInnerBoundaryWithName!(proj,name) + return l+1, chain +end +""" + +""" +function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + lst = chain["LIST"] + for crv in lst + if crv["name"] == curveName + return crv + end + end + return nothing +end +""" + innerBoundaryIndices(proj::Project, curveName::String) + +Returns (curveIndex,chainIndex) for the location of the curve named `curveName` +in it's inner boundary chain. +""" +function innerBoundaryIndices(proj::Project, curveName::String) +# +# For each inner boundary curve chain +# + chains = getAllInnerBoundaries(proj) + for (j,chain) in enumerate(chains) + crvList = chain["LIST"] + for (i,crv) in enumerate(crvList) + if crv["name"] == curveName + return i,j + end + end + end + return (0,0) +end +# +# -------------------------------------------------------------------------------------- +# +function getModelDict(proj::Project) + if haskey(proj.projectDictionary,"MODEL") + return proj.projectDictionary["MODEL"] + else + modelDict = Dict{String,Any}() + proj.projectDictionary["MODEL"] = modelDict + modelDict["TYPE"] = "MODEL" + return modelDict + end +end + +function getDictInModelDictNamed(proj::Project,name::String) + modelDict = getModelDict(proj) + + if haskey(modelDict,name) + return modelDict[name] + else + d = Dict{String,Any}() + modelDict[name] = d + d["TYPE"] = name + return d + end +end diff --git a/HQMTool/Source/Project/Project.jl b/HQMTool/Source/Project/Project.jl new file mode 100644 index 00000000..b64c83fa --- /dev/null +++ b/HQMTool/Source/Project/Project.jl @@ -0,0 +1,409 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# +#= + The Project is the controller in an MVC paradigm. It manages the model, + stored in the projectDictionary, and plotting data, and responds to enableNotifications + of changes. +=# +mutable struct Project + name::String + projectDirectory:: String + projectDictionary::Dict{String,Any} + plt::Any #For the plot + plotOptions::Int # = combinations of MODEL, GRID, MESH +# +# For drawing +# + outerBndryPoints ::Array{Any} # CHAIN + outerBndryNames ::Array{String} + innerBoundaryPoints ::Array{Any} # Array of CHAINs + innerBoundaryNames ::Array{Any} # Array of CHAINs of names + innerBoundaryChainNames::Array{String} # Array of the names of the CHAINs + refinementRegionPoints ::Array{Array{Float64,2}} # Array of Array of points + refinementRegionNames ::Array{String} + refinementRegionLoc ::Array{Array{Float64}} # Center point of a refinement region + bounds ::Array{Float64} + userBounds ::Array{Float64} + xGrid ::Array{Float64} + yGrid ::Array{Float64} + xMesh ::Array{Float64} + yMesh ::Array{Float64} + backgroundGridShouldUpdate::Bool + meshShouldUpdate ::Bool +end + +defaultPlotPts = 50 +meshFileFormats = Set(["ISM", "ISM-V2"]) +plotFileFormats = Set(["sem", "skeleton"]) +smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) +statusValues = Set(["ON", "OFF"]) +refinementTypes = Set(["smooth", "sharp"]) + +include("./ControlInputAPI.jl") +include("./BackgroundGridAPI.jl") +include("./ModelAPI.jl") +include("./RefinementRegionsAPI.jl") +include("./RunParametersAPI.jl") +include("./SmootherAPI.jl") + +""" + openProject(fileName::String, folder::String) + +Open existing project described in the control File. + + folder = folder the control file is in + fileNmae = the name of the file +""" +function openProject(fileName::String, folder::String) + + controlFile = joinpath(folder,fileName) + splitName = split(fileName,".") + + controlDict = ImportControlFile(controlFile) + + s = string(splitName[1]) # This is dumb + proj = newProject(s,folder) +# +# Overwrite defaults +# + proj.projectDictionary = controlDict + + assemblePlotArrays(proj) + clearUndoRedo() + + return proj +end +""" + saveProject(proj::Project) + + proj = Project to be saved +Save a project dictionary to the file path specified when the project was created. +""" +function saveProject(proj::Project) + getfolder = mkpath(proj.projectDirectory) + fileName = joinpath(proj.projectDirectory,proj.name)*".control" + WriteControlFile(proj.projectDictionary,fileName) +end +""" + newProject(name::String, folder::String) + +Create a new project with the given name. That name will be used +for the mesh and plot files in the specified folder. +""" +function newProject(name::String, folder::String) + ibChainPoints = Any[] + ibChainNames = String[] + ibNames = Any[] + obNames = String[] + obPnts = Any[] + projectDict = Dict{String,Any}() + plt = nothing + undoStack = Any[] + redoStack = Any[] + bounds = emptyBounds() # top, left, bottom, right + userBounds = emptyBounds() + xGrid = Float64[] + yGrid = Float64[] + xMesh = Float64[] + yMesh = Float64[] + refinementRegionPts = Array{Array{Float64,2}}[] + refinementRegionNames = Array{String}[] + refinementRegionLocs = Array{Array{Float64}}[] + plotOptions = 0 +# + proj = Project(name, folder, projectDict, plt, plotOptions, obPnts, obNames, + ibChainPoints,ibNames, ibChainNames, + refinementRegionPts,refinementRegionNames, refinementRegionLocs, + bounds, userBounds, xGrid, yGrid, xMesh, yMesh, + true, false) + + addObserver(proj,"CURVE_DID_CHANGE_NOTIFICATION",curveDidChange) + addObserver(proj,"MODEL_DID_CHANGE_NOTIFICATION",modelDidChange) + addObserver(proj,"BGRID_DID_CHANGE_NOTIFICATION",backgroundGridDidChange) + addObserver(proj,"MESH_WAS_GENERATED_NOTIFICATION",meshWasGenerated) + addObserver(proj,"MESH_WAS_DELETED_NOTIFICATION",meshWasDeleted) + addObserver(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",refinementWasAdded) + addObserver(proj,"REFINEMENT_WAS_CHANGED_NOTIFICATION",refinementDidChange) + enableNotifications() +# +# Set some default values +# + addRunParameters!(proj) + addSpringSmoother!(proj) + enableUndo() + return proj +end +""" +hasBackgroundGrid(proj::Project) + +Tests to see if the project has a backgroundGrid dictionary defined. +""" +function hasBackgroundGrid(proj::Project) + controlDict = getControlDict(proj) + if haskey(controlDict,"BACKGROUND_GRID") + return true + else + return false + end +end + +function assemblePlotArrays(proj::Project) + + empty!(proj.outerBndryPoints) + empty!(proj.outerBndryNames) + empty!(proj.innerBoundaryChainNames) + empty!(proj.innerBoundaryPoints) + empty!(proj.innerBoundaryNames) + empty!(proj.xGrid) + empty!(proj.yGrid) + + bounds = emptyBounds() + + modelDict = getModelDict(proj) + + if haskey(modelDict,"OUTER_BOUNDARY") + outerBoundary = modelDict["OUTER_BOUNDARY"] + obChain = outerBoundary["LIST"] + proj.outerBndryPoints = chainPoints(obChain,defaultPlotPts) + + chB = chainBounds(proj.outerBndryPoints) + bounds = bboxUnion(bounds,chB) + + for crv in obChain + push!(proj.outerBndryNames,crv["name"]) + end + end + + if haskey(modelDict,"INNER_BOUNDARIES") + innerBoundaries = modelDict["INNER_BOUNDARIES"] + innerBoundaryList = innerBoundaries["LIST"] #LIST of CHAINS + for d in innerBoundaryList + push!(proj.innerBoundaryChainNames, d["name"]) + ibChain = d["LIST"] + ibPnts = chainPoints(ibChain,defaultPlotPts) + push!(proj.innerBoundaryPoints,ibPnts) + chB = chainBounds(ibPnts) + bounds = bboxUnion(bounds,chB) + names = String[] + for crv in ibChain + push!(names,crv["name"]) + end + push!(proj.innerBoundaryNames,names) + end + end + + controlDict = getControlDict(proj) + + if haskey(controlDict,"REFINEMENT_REGIONS") + refinementBlock = controlDict["REFINEMENT_REGIONS"] + refinementsList = refinementBlock["LIST"] + for ref in refinementsList + addRefinementRegionPoints!(proj,ref) + end + end + proj.bounds = bounds +end + +function projectBounds(proj::Project) + bounds = emptyBounds() + + if !isempty(proj.outerBndryPoints) + chB = chainBounds(proj.outerBndryPoints) + bounds = bboxUnion(bounds,chB) + end + + if !isempty(proj.innerBoundaryPoints) + for i = 1:length(proj.innerBoundaryPoints) + ibPnts = proj.innerBoundaryPoints[i] + chB = chainBounds(ibPnts) + bounds = bboxUnion(bounds,chB) + end + end + return bounds +end + +function projectGrid(proj::Project) + + controlDict = proj.projectDictionary["CONTROL_INPUT"] + + if haskey(controlDict,"BACKGROUND_GRID") + bgDict = controlDict["BACKGROUND_GRID"] + + if haskey(bgDict,"dx") + N = intArrayForKeyFromDictionary("N", bgDict) + x0 = realArrayForKeyFromDictionary("x0",bgDict) + left = x0[1] + bottom = x0[2] + xGrid = zeros(Float64, N[1]+1) + yGrid = zeros(Float64, N[2]+1) + dx = realArrayForKeyFromDictionary("dx", bgDict) + for i = 1:N[1]+1 + xGrid[i] = left + (i-1)*dx[1] + end + for j = 1:N[2]+1 + yGrid[j] = bottom + (j-1)*dx[2] + end + else + dx = realArrayForKeyFromDictionary("background grid size", bgDict) + bounds = proj.bounds + + width = bounds[RIGHT] - bounds[LEFT] + height = bounds[TOP] - bounds[BOTTOM] + + Nx = Int(round(width/dx[1])) + 3 # Want the model inside the grid + Ny = Int(round(height/dx[2])) + 3 + + xGrid = zeros(Float64, Nx) + yGrid = zeros(Float64, Ny) + + for i = 1:Nx + xGrid[i] = bounds[LEFT] + (i-2)*dx[1] # Arrays start at 1, ugh. + end + for j = 1:Ny + yGrid[j] = bounds[BOTTOM] + (j-2)*dx[2] + end + end + end + + return xGrid, yGrid +end +# +# NOTIFICATION ACTIONS +# +function curveDidChange(proj::Project,crv::Dict{String,Any}) + curveName = getCurveName(crv) +# +# Find the curve location: See if the curve is in the outer boundary +# + for (i,s) in enumerate(proj.outerBndryNames) + if s == curveName + proj.outerBndryPoints[i] = curvePoints(crv,defaultPlotPts) + if !isnothing(proj.plt) + options = proj.plotOptions + updatePlot!(proj, options) + end + return nothing + end + end +# +# Otherwise, see if it is an inner boundary +# + crvNumber, bndryNumber = innerBoundaryIndices(proj,curveName) + if crvNumber == 0 || bndryNumber == 0 + return nothing + end + innerBoundaryPoints = proj.innerBoundaryPoints[bndryNumber] + innerBoundaryPoints[crvNumber] = curvePoints(crv,defaultPlotPts) + proj.backgroundGridShouldUpdate = true + + if !isnothing(proj.plt) + options = proj.plotOptions + updatePlot!(proj, options) + end + return nothing +end + +function modelDidChange(proj::Project, sender::Project) + + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (options & MODEL) == 0 + options = options + MODEL + end + updatePlot!(proj, options) + end +end + +function backgroundGridDidChange(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + proj.backgroundGridShouldUpdate = true + options = proj.plotOptions + if (options & GRID) == 0 + options = options + GRID + end + updatePlot!(proj, options) + end +end + +function refinementWasAdded(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (options & REFINEMENTS) == 0 + options = options + REFINEMENTS + end + updatePlot!(proj, options) + end +end + +function refinementDidChange(proj::Project, sender::Dict{String,Any}) + regionName = sender["name"] + lst = getAllRefinementRegions(proj) + indx = 0 + for (i,r) in enumerate(lst) + if r["name"] == regionName + indx = i + break + end + end + + if indx > 0 + x = refinementRegionPoints(sender) + proj.refinementRegionPoints[indx] = x + proj.refinementRegionNames[indx] = sender["name"] + center = refinementRegionCenter(sender) + proj.refinementRegionLoc[indx] = center + + if !isnothing(proj.plt) + options = proj.plotOptions + if (options & REFINEMENTS) == 0 + options = options + REFINEMENTS + end + updatePlot!(proj, options) + end + else + println("Refinement region with name $regionName not found.") + end +end + +function meshWasGenerated(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + options = (MODEL & options) + MESH + proj.meshShouldUpdate = true + updatePlot!(proj, options) + end +end + +function meshWasDeleted(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (MESH & options) > 0 + options = options - MESH + end + proj.meshShouldUpdate = false + updatePlot!(proj, options) + end +end diff --git a/HQMTool/Source/Project/RefinementRegionsAPI.jl b/HQMTool/Source/Project/RefinementRegionsAPI.jl new file mode 100644 index 00000000..1c439034 --- /dev/null +++ b/HQMTool/Source/Project/RefinementRegionsAPI.jl @@ -0,0 +1,476 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" +newRefinementCenter(type, + center, meshSize, + width ) + +Create refinement center of `type` "smooth" or "sharp" centered at `center = [x,y,z]`` +with a mesh size `meshSize` spread over a radius `width`. +""" +function newRefinementCenter(name::String, type::String, + x0::Array{Float64}, h::Float64, + w::Float64 ) + disableUndo() + disableNotifications() + centerDict = Dict{String,Any}() + centerDict["TYPE"] = "REFINEMENT_CENTER" + setRefinementType!(centerDict,type) + setRefinementLocation!(centerDict,x0) + setRefinementGridSize!(centerDict,h) + setRefinementWidth!(centerDict,w) + setRefinementName!(centerDict,name) + enableNotifications() + enableUndo() + return centerDict +end +""" + addRefinementRegion!(proj::Project,r::Dict{String,Any}) + +Add the refinement region to the project +""" +function addRefinementRegion!(proj::Project,r::Dict{String,Any}) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + push!(lst,r) + addRefinementRegionPoints!(proj,r) + enableUndo() + registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Add Refinement Region") + enableNotifications() + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +""" + addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) + +Compute and add to the project the plotting points for the refinement region +""" +function addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) + + x = refinementRegionPoints(r) + push!(proj.refinementRegionPoints,x) + push!(proj.refinementRegionNames, r["name"]) + center = refinementRegionCenter(r) + push!(proj.refinementRegionLoc,center) +end +""" + refinementRegionPoints(r::Dict{String,Any}) + + Returns Array{Float64,2} being the plotting points of a refinement region +""" +function refinementRegionPoints(r::Dict{String,Any}) + + if r["TYPE"] == "REFINEMENT_CENTER" + center = getRefinementLocation(r) + radius = getRefinementWidth(r) + + N = defaultPlotPts + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + arcCurvePoints(center,radius,0.0,360.0,"degrees",t,x) + return x + else + xStart = realArrayForKeyFromDictionary("x0",r) + xEnd = realArrayForKeyFromDictionary("x1",r) + dx = xEnd - xStart + l = sqrt(dx[1]^2 + dx[2]^2) + w = realForKeyFromDictionary("w",r) + v = [-dx[2]/l,dx[1]/l] + x1 = xStart[1:2] + w*v + x2 = xEnd[1:2] + w*v + v = [dx[2]/l,-dx[1]/l] + x3 = xEnd[1:2] + w*v + x4 = xStart[1:2] + w*v + x = zeros(Float64,5,2) + x[1,:] = x1 + x[2,:] = x2 + x[3,:] = x3 + x[4,:] = x4 + x[5,:] = x1 + return x + end + +end +""" + refinementRegionCenter(r::Dict{String,Any}) + +Get, or compute, the center of the given refinement region. +""" +function refinementRegionCenter(r::Dict{String,Any}) + if r["TYPE"] == "REFINEMENT_CENTER" + center = getRefinementLocation(r) + return center[1:2] + else + xStart = realArrayForKeyFromDictionary("x0",r) + xEnd = realArrayForKeyFromDictionary("x1",r) + xAvg = 0.5*(xStart + xEnd) + return xAvg[1:2] + end +end +""" + removeRefinementRegion!(proj::Project, name::String) + +Delete the named refinement region. +""" +function removeRefinementRegion!(proj::Project, name::String) + i,r = getRefinementRegion(proj,name) + lst = getAllRefinementRegions(proj) + deleteat!(lst,i) + deleteat!(proj.refinementRegionLoc,i) + deleteat!(proj.refinementRegionNames,i) + deleteat!(proj.refinementRegionPoints,i) + registerWithUndoManager(proj,insertRefinementRegion!, (r,i,), "Remove Refinement Region") + enableNotifications() + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +""" + insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) + +Used by undo() +""" +function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) + lst = getAllRefinementRegions(proj) + registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Set Insert Refinement Region") + insert!(lst,indx,r) + x = refinementRegionPoints(r) + insert!(proj.refinementRegionPoints,indx,x) + center = refinementRegionCenter(r) + insert!(proj.refinementRegionLoc,indx,center) + insert!(proj.refinementRegionNames,indx,r["name"]) + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + newRefinementLine(type, + start, end, + meshSize, + width ) + +Create refinement line of type "smooth" or "sharp" between `start` = [x,y,z] and `end` = [x,y,z] +with a mesh size `meshSize` spread over a width `width`. +""" +function newRefinementLine(name::String, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64 ) + disableUndo() + disableNotifications() + lineDict = Dict{String,Any}() + lineDict["TYPE"] = "REFINEMENT_LINE" + setRefinementType(lineDict,type) + setRefinementStart(lineDict,x0) + setRefinementEnd(lineDict,x1) + setRefinementGridSize(lineDict,h) + setRefinementWidth(lineDict,w) + setRefinementName!(lineDict,name) + enableNotifications() + enableUndo() + return lineDict +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementRegion(proj::Project, indx) + +Get the refinement region with index, indx from the project. Returns nothing if +there is none. The return value is a dictionary that represents the refinement region. +""" +function getRefinementRegion(proj::Project, indx::Int) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + if indx > length(lst) + printf("Index %i is larger than the number of refinement regions, %i", indx, length(lst)) + return nothing + end + return lst[indx] +end +# +# -------------------------------------------------------------------------------------- +# +""" + allRefinementRegions(proj::Project) + +Get the list of refinement regions. +""" +function getAllRefinementRegions(proj::Project) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + return lst +end +# +# -------------------------------------------------------------------------------------- +# +""" + (i,r) = getRefinementRegion(project, name) + +Get the refinement region with the given name and its location in the list of refinement regions. +""" +function getRefinementRegion(proj::Project, name::String) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + for (i,r) in enumerate(lst) + if r["name"] == name + return i,r + end + end + println("Refinement region with name %s not found",name) + return nothing +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementType!(refinementRegion, type) + +Set the type, either "smooth" or "sharp" for the given refinement region. +""" +function setRefinementType!(r::Dict{String,Any}, type::String) + if !in(type,refinementTypes) + println("Acceptable refinement types are `smooth` and `sharp`. Try again.") + return + end + + if haskey(r,"type") + oldType = r["type"] + registerWithUndoManager(r,setRefinementType!, (oldType,), "Set Refinement Type") + end + r["type"] = type +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementType(r::Dict{String,Any}) + +Return the type of refinement, either "smooth" or "sharp". `r` is the dictionary that +represents the refinement region. +""" +function getRefinementType(r::Dict{String,Any}) + return r["type"] +end +""" + setRefinementName!(r::Dict{String,Any}, type) + +Set a name for the refinement region.`r` is the dictionary that + represents the refinement region. +""" +function setRefinementName!(r::Dict{String,Any}, name::String) + if haskey(r,"name") + oldName = r["name"] + registerWithUndoManager(r,setRefinementName!, (oldName,), "Set Refinement Name") + end + r["name"] = name + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementName(r::Dict{String,Any}) + +Return name of the refinement. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementName(r::Dict{String,Any}) + return r["name"] +end# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementLocation!(refinementCenter, location) + +Set the location of a refinement center to location = [x,y,z]. +""" +function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) + return nothing +end + +function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") + end + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementLocation(r::Dict{String,Any}) + +Return Array{Float64} of the location of the refinement center.`r` is the dictionary that +represents the refinement region. +""" +function getRefinementLocation(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x0",r) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementGridSize(r::Dict{String,Any}, h) + +Set the grid size, `h` for the refinement region. `r` is the dictionary that +represents the refinement region. +""" +function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) + if haskey(r,"h") + old = r["h"] + registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") + end + r["h"] = string(h) +end +function setRefinementGridSize!(r::Dict{String,Any}, h::String) + hf = parse(Float64,h) + setRefinementGridSize!(r,hf) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementGridSize(r::Dict{String,Any}) + +Returns the grid size,h, as Float64. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementGridSize(r::Dict{String,Any}) + return parse(Float64,r["h"]) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementWidth!(r::Dict{String,Any}, width) + +Set the width of the refinement region. `r` is the dictionary that +represents the refinement region. +""" +function setRefinementWidth!(r::Dict{String,Any},w::Float64) + if haskey(r,"w") + old = r["w"] + registerWithUndoManager(r,setRefinementWidth!, (old,), "Set Refinement Width") + end + r["w"] = string(w) + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +function setRefinementWidth!(r::Dict{String,Any},w::String) + wf = parse(Float64,w) + setRefinementWidth!(r,wf) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementWidth(r::Dict{String,Any}) + +Returns the region width,w, as Float64. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementWidth(r::Dict{String,Any}) + return parse(Float64,r["w"]) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementStart!(refinementRegion, location) + +Set the start point location of a refinement line, `location = [x, y, z]`. +""" +function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(r,)) +end +function setRefinementStart!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") + end + r["x0"] = x0Str +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementStart (r::Dict{String,Any}) + +Return Array{Float64} of the start location of the refinement line. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementStart(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x0",r) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementEnd(refinementRegion, location) + +Set the end point location of a refinement line, `location = [x, y, z]`. +""" +function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x1") + old = r["x1"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x1"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x1") + old = r["x1"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") + end + r["x1"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementEnd(r::Dict{String,Any}) + +Return Array{Float64} of the end location of the refinement line +""" +function getRefinementEnd(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x1",r) +end diff --git a/HQMTool/Source/Project/RunParametersAPI.jl b/HQMTool/Source/Project/RunParametersAPI.jl new file mode 100644 index 00000000..cd51b452 --- /dev/null +++ b/HQMTool/Source/Project/RunParametersAPI.jl @@ -0,0 +1,190 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) + +Add a RUN_PARAMETERS block and set all the parameters in one call. +""" +function addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) + + setFileNames!(proj) + setPlotFileFormat!(proj,plotFormat) + setMeshFileFormat!(proj,meshFileFormat) + setPolynomialOrder!(proj,polynomialOrder) + + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + registerWithUndoManager(proj,removeRunParameters!, (nothing,), "Add Run Parameters") + + return rpDict +end +""" + removeRunParameters!(proj::Project) + +Remove the run parameters block from the project. +""" +function removeRunParameters!(proj::Project) + cDict = getControlDict(proj) + if haskey(cDict,"RUN_PARAMETERS") + delete!(cDict,"RUN_PARAMETERS") + end +end + +""" + setName(proj::Project,name::String) + +The `name` of the project is the filename to be used by the mesh, plot, and +stats files. It is also the name of the control file the tool will produce. +""" +function setName!(proj::Project,name::String) + + oldName = proj.name + registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") + proj.name = name + setFileNames!(proj) +end +""" + getName(proj::Project) + +Returns the filename to be used by the mesh, plot, control, and +stats files. +""" +function getName(proj::Project) + return proj.name +end +""" +setFolder(proj::Project,folder::String) + +Set the path to the directory where the mesh, plot, control, and stats files +will be written +""" +function setFolder(proj::Project,folder::String) + oldPath = proj.path + registerWithUndoManager(proj,setFolder,(oldPath,),"Set Project Folder") + proj.path = folder +end +""" + path(proj::Project) + +Returns the directory where the project files will be written +""" +function getfolder(proj::Project) + return proj.path +end +""" + setPolynomialOrder(proj::Project, p::Int) + +Set the polynomial order for boundary curves in the mesh file to `p`. +""" +function setPolynomialOrder!(proj::Project, p::Int) + key = "polynomial order" + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + if haskey(rpDict,key) + oldP = parse(Int,rpDict[key]) + registerWithUndoManager(proj,setPolynomialOrder!,(oldP,),"Set Order") + end + rpDict["polynomial order"] = string(p) +end +""" + getPolynomialOrder(proj::Project) + +Returns the polynomial order for boundary curves in the mesh file. +""" +function getPolynomialOrder(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["polynomial order"] +end +""" + setMeshFileFormat(proj::Project, meshFileFormat::String) + +Set the file format for the mesh file. Acceptable choices +are "ISM" and "ISM-V2". +""" +function setMeshFileFormat!(proj::Project, meshFileFormat::String) + if !in(meshFileFormat,meshFileFormats) + println("Acceptable file formats are ISM and ISM-V2. Try again.") + return + end + key = "mesh file format" + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + if haskey(rpDict,key) + oldFormat = rpDict[key] + registerWithUndoManager(proj,setMeshFileFormat!,(oldFormat,),"Set Mesh Format") + end + rpDict[key] = meshFileFormat +end +""" + getMeshFileFormat(proj::Project) + +Returns the format in which the mesh will be written. +""" +function getMeshFileFormat(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["mesh file format"] +end +""" + setPlotFileFormat(proj::Project, plotFileFormat::String) + +Set the file format for the plot file. Acceptable choices +are "sem", which includes interior nodes and boundary nodes and "skeleton", which includes +only the corner nodes. +""" +function setPlotFileFormat!(proj::Project, plotFileFormat::String) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + key = "plot file format" + if haskey(rpDict,key) + oldFormat = rpDict[key] + registerWithUndoManager(proj,setPlotFileFormat!,(oldFormat,),"Set Plot Format") + end + rpDict[key] = plotFileFormat +end +""" + getPlotFileFormat(proj::Project) + +Returns the plot file format. +""" +function getPlotFileFormat(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["plot file format"] +end + +function setFileNames!(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") + rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") + rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") + end + + function getMeshFileName(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["mesh file name"] + end diff --git a/HQMTool/Source/Project/SmootherAPI.jl b/HQMTool/Source/Project/SmootherAPI.jl new file mode 100644 index 00000000..eb046084 --- /dev/null +++ b/HQMTool/Source/Project/SmootherAPI.jl @@ -0,0 +1,118 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addSpringSmoother!(status::String, type::String, nIterations::Int) + + status is either `ON` or `OFF` + type is either `LinearSpring` or `LinearAndCrossbarSpring` + +""" +function addSpringSmoother!(proj::Project,status::String = "ON", + type::String = "LinearAndCrossbarSpring", + nIterations::Int = 25) + if !in(status,statusValues) + println("Acceptable smoother status are `ON` and `OFF`. Try again.") + return + end + if !in(type,smootherTypes) + println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + return + end + setSmoothingStatus!(proj,status) + setSmoothingType!(proj,type) + setSmoothingIterations!(proj,nIterations) +end +""" + setSmoothingStatus(proj:Project, status::String) + +status is either "ON" or "OFF" +""" +function setSmoothingStatus!(proj::Project, status::String) + if !in(status,statusValues) + println("Acceptable smoother status are `ON` and `OFF`. Try again.") + return + end + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["smoothing"] = status +end +""" + smoothingStatus(proj::Project) + +Returns whether the smoother will be "ON" or "OFF" +""" +function getSmoothingStatus(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["smoothing"] +end +""" +setSmoothingType!(proj:Project, status::String) + +type is either `LinearSpring` or `LinearAndCrossbarSpring` +""" +function setSmoothingType!(proj::Project, type::String) + if !in(type,smootherTypes) + println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + return + end + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["smoothing type"] = type +end +""" + smoothingType(proj::Project) + +Returns either "LinearSpring" or "LinearAndCrossbarSpring" +""" +function getSmoothingType(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["smoothing type"] +end +""" + setSmoothingIterations!((proj::Project, iterations::Int) + +Set the number of iterations to smooth the mesh. +""" +function setSmoothingIterations!(proj::Project, iterations::Int) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["number of iterations"] = iterations +end +""" + +""" +function getSmoothingIterations(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["number of iterations"] + +end +""" + removeSpringSmoother!(proj::Project) + +Remove the background grid block from the project. +""" +function removeSpringSmoother!(proj::Project) + cDict = getControlDict(proj) + delete!(cDict,"SPRING_SMOOTHER") +end diff --git a/HQMTool/Source/Project/Undo.jl b/HQMTool/Source/Project/Undo.jl new file mode 100644 index 00000000..c14438f3 --- /dev/null +++ b/HQMTool/Source/Project/Undo.jl @@ -0,0 +1,142 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +struct UROperation + object::Any + action::Any + data ::Tuple + name ::String +end + +@enum UNDO_OPERATION_TYPE begin + UNDO_USER_OPERATION = 0 + UNDO_OPERATION = 1 + REDO_OPERATION = 2 + UNDO_IGNORE = 3 +end + +#= +TODO: The undo framework currently works globally, within the REPL. It *should* work project-by-project. +To make it project based, undo() would be replaced by undo(project) and an .undoStack +property of the project would replace HQMglobalUndoStack. This is +not a big deal except if multiple projects are open, and muliple objects like curves have been +defined but not added to a project. In interactive mode curves are separate from projects until +added. (The same curve could be added to multiple projects.) So some logic needs to be +figured out before modifying below. If only one project is managed per session, +then this is not a problem. +=# +HQMglobalUndoStack = [] +HQMglobalRedoStack = [] +HQMglobalChangeOP = UNDO_IGNORE + +function undo() + if !isempty(HQMglobalUndoStack) + op = pop!(HQMglobalUndoStack) + f = op.action + d = op.data + obj = op.object + global HQMglobalChangeOP = UNDO_OPERATION + if isnothing(d[1]) + f(obj) + else + f(obj,d...) + end + global HQMglobalChangeOP = UNDO_USER_OPERATION + return "Undo "*op.name + end + return "Empty undo stack. No action performed." +end + +function redo() + if !isempty(HQMglobalRedoStack) + op = pop!(HQMglobalRedoStack) + f = op.action + d = op.data + obj = op.object + global HQMglobalChangeOP = REDO_OPERATION + if isnothing(d[1]) + f(obj) + else + f(obj,d...) + end + global HQMglobalChangeOP = UNDO_USER_OPERATION + return "Redo " * op.name + end + return "Empty redo stack. No action performed." +end + +function registerUndo(obj, action, data::Tuple, name::String) + uOp = UROperation(obj,action,data,name) + push!(HQMglobalUndoStack,uOp) +end + +function registerWithUndoManager(obj, action, oldData::Tuple, name::String) + + if HQMglobalChangeOP == UNDO_USER_OPERATION #User action + registerUndo(obj,action,oldData,name) + elseif HQMglobalChangeOP == UNDO_OPERATION #Undo operation + registerRedo(obj,action,oldData,name) + elseif HQMglobalChangeOP == REDO_OPERATION #Redo operation + registerUndo(obj,action,oldData,name) + else + # UNDO_IGNORE + end +end + +function registerRedo(obj, action, data::Tuple, name::String) + rOp = UROperation(obj,action,data,name) + push!(HQMglobalRedoStack,rOp) +end + +function clearUndoRedo() + empty!(HQMglobalUndoStack) + empty!(HQMglobalRedoStack) +end + +function undoActionName() + if !isempty(HQMglobalUndoStack) + op = last(HQMglobalUndoStack) + return op.name + end + return "No undo action in queue" +end + + +function redoActionName() + if !isempty(HQMglobalRedoStack) + op = last(HQMglobalRedoStack) + return op.name + end + return "No redo action in queue" +end + +function disableUndo() + global HQMglobalChangeOP = UNDO_IGNORE +end + +function enableUndo() + global HQMglobalChangeOP = UNDO_USER_OPERATION +end diff --git a/HQMTool/Source/Viz/VizMesh.jl b/HQMTool/Source/Viz/VizMesh.jl new file mode 100644 index 00000000..452e9f2c --- /dev/null +++ b/HQMTool/Source/Viz/VizMesh.jl @@ -0,0 +1,78 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +function getMeshFromMeshFile(meshFile::AbstractString) + + open(meshFile,"r") do f + line = strip(readline(f)) #Header Should be ISM-V2 + if line != "ISM-V2" + error("Mesh file must be ISM-V2") + return nothing + end + line = readline(f) # Numbers of nodes, edges ... + values = split(line) + + nNodes = parse(Int,values[1]) + nEdges = parse(Int,values[2]) +# +# Read the nodes +# + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64,values[j]) + end + end +# +# Read the edges and construct the lines array +# + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) + + for i = 1:3:3*nEdges + + values = split(readline(f)) + n = parse(Int,values[1]) + m = parse(Int,values[2]) + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN + + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + + end + return xMesh, yMesh + end + +end + +function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) + lines!(plt[1,1], xMesh,yMesh) +end diff --git a/HQMTool/Source/Viz/VizProject.jl b/HQMTool/Source/Viz/VizProject.jl new file mode 100644 index 00000000..8104037e --- /dev/null +++ b/HQMTool/Source/Viz/VizProject.jl @@ -0,0 +1,194 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using GLMakie + +const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 +const REFINEMENTS = 8; const ALL = 15 +""" + plotProject!(proj::Project, plotOptions::Int = 0) + +Plot objects specified by the `plotOptions`. Construct the `plotOptions` by the sum +of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. + +Example: To plot the model and the grid, `plotOptions = MODEL + GRID`. To plot +just the mesh, `plotOptions = MESH`. + +To plot everything, `plotOptions = MODEL + GRID + MESH + REFINEMENTS` + +Contents are overlayed in the order: GRID, MESH, MODEL, REFINEMENTS +""" +function plotProject!(proj::Project, plotOptions::Int = 0) + + if isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + end + plt = proj.plt + ax = plt[1,1] = Axis(plt) + + plotTheModel = ((plotOptions & MODEL) != 0) + plotTheGrid = ((plotOptions & GRID) != 0) + plotTheMesh = ((plotOptions & MESH) != 0) + plotTheRefinements = ((plotOptions & REFINEMENTS) != 0) + proj.plotOptions = plotOptions +# +# Plot the grid +# + if plotTheGrid && hasBackgroundGrid(proj) + if proj.backgroundGridShouldUpdate # Lazy evaluation of the background grid + proj.bounds = projectBounds(proj) + proj.xGrid, proj.yGrid = projectGrid(proj) + proj.backgroundGridShouldUpdate = false + end + nX = length(proj.xGrid) + nY = length(proj.yGrid) + z = zeros(Float64,nX,nY) + wireframe!(plt[1,1],proj.xGrid,proj.yGrid,z) + end +# +# Plot the mesh +# + if plotTheMesh + # Lazy creation of mesh plotting arrays + if proj.meshShouldUpdate || (isempty(proj.xMesh) && isempty(proj.yMesh)) + meshFileName = getMeshFileName(proj) + if isfile(meshFileName) + proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName) + plotMesh(plt, proj.xMesh, proj.yMesh) + end + proj.meshShouldUpdate = false + else + plotMesh(plt, proj.xMesh, proj.yMesh) + end + end +# +# Plot the model +# + if plotTheModel +# +# Plot the outer innerBoundaries +# + if !isempty(proj.outerBndryNames) + plotNames = ["Outer."*s for s in proj.outerBndryNames] + plotChain!(plt,proj.outerBndryPoints, plotNames) + end +# +# Plot the inner innerBoundaries +# + if !isempty(proj.innerBoundaryChainNames) + for i = 1:length(proj.innerBoundaryChainNames) + innerBndryPts = proj.innerBoundaryPoints[i] + innerBndryNames = [ proj.innerBoundaryChainNames[i]*"."*s for s in proj.innerBoundaryNames[i]] + plotChain!(plt,innerBndryPts, innerBndryNames) + end + end + if !isempty(proj.outerBndryNames) || !isempty(proj.innerBoundaryChainNames) + plt[1,2] = Legend(plt, ax, "Curves", framevisible = false, labelsize = 24, titlesize = 28) + end + + end +# +# Plot refinement regions +# + if plotTheRefinements + if !isempty(proj.refinementRegionNames) + plotRefinement(plt,proj.refinementRegionPoints, + proj.refinementRegionNames, + proj.refinementRegionLoc) + end + end +# +# Display the plot +# + ax.aspect = DataAspect() + display(plt) +end +""" + updatePlot!(proj::Project) + +This version replots the figure with the current options. Legacy. +""" +function updatePlot!(proj::Project) + if !isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + plotOptions = proj.plotOptions + plotProject!(proj, plotOptions) + end +end +""" +updatePlot!(proj::Project, plotOptions::Int) + +Replot with the new plotOptions = combinations (sums) of + + GRID, MESH, MODEL, REFINEMENTS + +Example: updatePlot(p, MESH + MODEL) +""" +function updatePlot!(proj::Project, plotOptions::Int) + if !isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + plotProject!(proj, plotOptions) + end +end + +function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) + x = chainPoints[1] + plotCurve(plt, x, labels[1]) + + s = length(labels) + + for i = 2:s + x = chainPoints[i] + plotCurve(plt,x,labels[i]) + end +end + +function plotCurve(plt, points::Matrix{Float64}, label::String) + lines!(plt[1,1],points[:,1],points[:,2], label = label, linewidth = 5 ) + s = size(points) + np = div(s[1], 2, RoundNearest) + if s[1] == 3 + np = 2 + end + dx = points[np+1,1] - points[np-1,1] + dy = points[np+1,2] - points[np-1,2] + theta = atan(dy,dx) + if(abs(dy) <= 0.0001) #Not pretty + theta = 0.0 + end + pp = (points[np,1],points[np,2]) + text!(plt[1,1],label,position = pp, align = (:center,:center), rotation = theta ) +end + +function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String}, loc::Array{Array{Float64}}) + + for (i,reg) in enumerate(points) + lines!(plt[1,1],reg[:,1],reg[:,2], label = label[i], linewidth = 5, linestyle = :dot, color=:black ) + p = loc[i] + pp = (p[1],p[2]) + text!(plt[1,1],label[i],position = pp, align = (:center,:center)) + end +end From e3b5b5c16f59d804792c9e79ab871f0dbdba6cce Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Sat, 11 Sep 2021 11:33:39 +0200 Subject: [PATCH 002/164] Integrate HQMTool into existing infrastructure (#11) * Integrate docs * Store png on GitHub * Push documentation previews * Fix docs; move sources * Move AllFeatures.control to examples folder * Add Printf dependency * Rearrange files * Fix path * Fix docs * Hopefully make tests pass again --- .gitignore | 2 + HQMTool/Doc/iceCreamCone.png | Bin 436345 -> 0 bytes Project.toml | 3 + docs/make.jl | 4 +- {HQMTool/Doc => docs/src}/CheatSheet.md | 22 ++-- {HQMTool/Doc => docs/src}/HQMTool.md | 105 +++++++++--------- .../Demo => examples}/AllFeatures.control | 0 .../ControlFile/ControlFileOperations.jl | 0 .../Source => src}/Curves/CurveOperations.jl | 0 {HQMTool/Source => src}/Curves/Spline.jl | 0 src/HOHQMesh.jl | 17 ++- {HQMTool => src}/HQMTool.jl | 28 +++-- {HQMTool/Source => src}/Mesh/Meshing.jl | 0 .../Misc/DictionaryOperations.jl | 0 .../Source => src}/Misc/NotificationCenter.jl | 0 {HQMTool/Source => src}/Model/Geometry.jl | 0 .../Project/BackgroundGridAPI.jl | 0 .../Source => src}/Project/ControlInputAPI.jl | 0 {HQMTool/Source => src}/Project/CurvesAPI.jl | 0 {HQMTool/Source => src}/Project/Generics.jl | 0 {HQMTool/Source => src}/Project/ModelAPI.jl | 0 {HQMTool/Source => src}/Project/Project.jl | 0 .../Project/RefinementRegionsAPI.jl | 0 .../Project/RunParametersAPI.jl | 0 .../Source => src}/Project/SmootherAPI.jl | 0 {HQMTool/Source => src}/Project/Undo.jl | 0 {HQMTool/Source => src}/Viz/VizMesh.jl | 0 {HQMTool/Source => src}/Viz/VizProject.jl | 2 - 28 files changed, 103 insertions(+), 80 deletions(-) delete mode 100644 HQMTool/Doc/iceCreamCone.png rename {HQMTool/Doc => docs/src}/CheatSheet.md (89%) rename {HQMTool/Doc => docs/src}/HQMTool.md (90%) rename {HQMTool/Demo => examples}/AllFeatures.control (100%) rename {HQMTool/Source => src}/ControlFile/ControlFileOperations.jl (100%) rename {HQMTool/Source => src}/Curves/CurveOperations.jl (100%) rename {HQMTool/Source => src}/Curves/Spline.jl (100%) rename {HQMTool => src}/HQMTool.jl (86%) rename {HQMTool/Source => src}/Mesh/Meshing.jl (100%) rename {HQMTool/Source => src}/Misc/DictionaryOperations.jl (100%) rename {HQMTool/Source => src}/Misc/NotificationCenter.jl (100%) rename {HQMTool/Source => src}/Model/Geometry.jl (100%) rename {HQMTool/Source => src}/Project/BackgroundGridAPI.jl (100%) rename {HQMTool/Source => src}/Project/ControlInputAPI.jl (100%) rename {HQMTool/Source => src}/Project/CurvesAPI.jl (100%) rename {HQMTool/Source => src}/Project/Generics.jl (100%) rename {HQMTool/Source => src}/Project/ModelAPI.jl (100%) rename {HQMTool/Source => src}/Project/Project.jl (100%) rename {HQMTool/Source => src}/Project/RefinementRegionsAPI.jl (100%) rename {HQMTool/Source => src}/Project/RunParametersAPI.jl (100%) rename {HQMTool/Source => src}/Project/SmootherAPI.jl (100%) rename {HQMTool/Source => src}/Project/Undo.jl (100%) rename {HQMTool/Source => src}/Viz/VizMesh.jl (100%) rename {HQMTool/Source => src}/Viz/VizProject.jl (99%) diff --git a/.gitignore b/.gitignore index 7f07f820..d1dad9a6 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ coverage/ coverage_report/ **/*.jl.*.cov .vscode/ +examples/*.tec +examples/*.mesh diff --git a/HQMTool/Doc/iceCreamCone.png b/HQMTool/Doc/iceCreamCone.png deleted file mode 100644 index 23511d2bc9342e0490b3c8cc01e6e67019f3b48f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436345 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

(R3ztIK~x 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üq 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%0Dr(21&z%>XKL|t4bbV$aAGv@ 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�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 MlK#c)3%CCMFNR>_Y5)KL diff --git a/Project.toml b/Project.toml index 80ad7966..1bf235bc 100644 --- a/Project.toml +++ b/Project.toml @@ -5,7 +5,10 @@ version = "0.1.1-pre" [deps] HOHQMesh_jll = "1d5cbd98-5122-5a8a-bea1-c186d986ee7f" +Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" +Requires = "ae029012-a4dd-5104-9daa-d747884805df" [compat] HOHQMesh_jll = "1.0" +Requires = "1.1.3" julia = "1.6" diff --git a/docs/make.jl b/docs/make.jl index a1594129..9381f223 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -23,6 +23,8 @@ makedocs( # Explicitly specify documentation structure pages = [ "Home" => "index.md", + "Interactive mesh generation" => "HQMTool.md", + "Cheat sheet" => "CheatSheet.md", "Reference" => "reference.md", "License" => "license.md" ], @@ -32,5 +34,5 @@ makedocs( deploydocs( repo = "github.com/trixi-framework/HOHQMesh.jl", devbranch = "main", - # push_preview = true + push_preview = true ) diff --git a/HQMTool/Doc/CheatSheet.md b/docs/src/CheatSheet.md similarity index 89% rename from HQMTool/Doc/CheatSheet.md rename to docs/src/CheatSheet.md index 05763e8a..49ed7d94 100644 --- a/HQMTool/Doc/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -1,4 +1,4 @@ -#HQMTool CheatSheet +# HQMTool CheatSheet Workflow: @@ -8,16 +8,16 @@ Workflow: 3. Add manual refinement (if desired) 5. Generate mesh -### Project +## Project p = newProject(,) -### Plotting +## [Plotting](@id cs-plotting) plotProject!(p,options) updatePlot!(p,options) -### Curves +## Curves c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* @@ -25,11 +25,11 @@ Workflow: c = new(name, dataFile) *Spline* c = new(name, nKnots, knotsMatrix) *also Spline* -### Manual Refinement +## [Manual Refinement](@id cs-manual-refinement) r = newRefinementCenter(name, center, gridSize, radius ) r = newRefinementLine(name,type, startPoint, endPoint, gridSize, width ) -### Adding to a Project +## Adding to a Project add!(p, c) *Add outer boundary curve* add!(p, c, ) *add curve to an inner boundary* @@ -38,14 +38,14 @@ Workflow: addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* -### Accessing items +## Accessing items crv = get(p,curveName) *Get a curve in the outer boundary* crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* r = getRefinementRegion(p, name) -### Removing from Project +## Removing from Project removeOuterboundary!(p) *Entire outer boundary curve* removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve @@ -53,12 +53,12 @@ Workflow: remove!(p, name, innerBoundaryName) *Curve in inner boundary* removeRefinementRegion!(p, name) -### Editing items +## Editing items All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. -### Meshing +## Meshing generateMesh(p) removeMesh!(p) - \ No newline at end of file + diff --git a/HQMTool/Doc/HQMTool.md b/docs/src/HQMTool.md similarity index 90% rename from HQMTool/Doc/HQMTool.md rename to docs/src/HQMTool.md index 8b2e8c40..da42ac40 100644 --- a/HQMTool/Doc/HQMTool.md +++ b/docs/src/HQMTool.md @@ -1,28 +1,28 @@ -#HQMTool +# HQMTool HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. ## Contents -1. [Introduction](#introduction) -2. [Basic Moves](#basicMoves) -3. [HQMTool API](#API) - 1. [Project Creation and Saving](#Project) - 2. [Plotting](#Plotting) - 3. [Modifying/Editing a Project](#EditingProject) - 4. [Controlling the Mesh Generation Process](#Control) - 1. [Editing the Run Parameters](#RunParameters) - 2. [Changing the output file names](#OutputFiles) - 3. [Adding the background grid](#BackgroundGrid) - 4. [Smoothing Operations](#Smoother) - 5. [Manual Refinement](#ManualRefinement) - 5. [Boundary Curves](#BoundaryCurves) - 1. [Adding and Removing Outer and Inner Boundaries](#AddingCurves) - 2. [Defining Curves](#DefiningCurves) - 3. [Editing Curves](#EditingCurves) - 6. [Undo/Redo](#Undo) -4. [Advanced](#Advanced) - -## Introduction +1. [Introduction](@ref) +2. [Basic Moves](@ref) +3. [HQMTool API](@ref) + 1. [Project Creation and Saving](@ref) + 2. [Plotting](@ref) + 3. [Modifying/Editing a Project](@ref) + 4. [Controlling the Mesh Generation Process](@ref) + 1. [Editing the Run Parameters](@ref) + 2. [Changing the output file names](@ref) + 3. [Adding the background grid](@ref) + 4. [Smoothing Operations](@ref) + 5. [Manual Refinement](@ref) + 5. [Boundary Curves](@ref) + 1. [Adding and Removing Outer and Inner Boundaries](@ref) + 2. [Defining Curves](@ref) + 3. [Editing Curves](@ref) + 6. [Undo/Redo](@ref) +4. [Advanced](@ref) + +## Introduction HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run @@ -98,7 +98,11 @@ One run parameter that must be set manually is the background grid. Since there The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. The script finishes by generating the quad mesh and plotting the results, as shown below -![](iceCreamCone.png) It also returns the project so that it can be edited further, if desired. +```@raw html +iceCreamCone +``` + +It also returns the project so that it can be edited further, if desired. To save a control file for HOHQMesh, simply invoke @@ -108,7 +112,7 @@ where outFile is the name of the control file (traditionally with a .control ext Methods are available to edit a model. For example to move the center of the outer boundary -## Basic Moves +## Basic Moves To create generate a mesh you @@ -158,29 +162,30 @@ To create generate a mesh you The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. -#HQMTool API -# Project Creation and Saving +## HQMTool API + +### Project Creation and Saving -### New Project +#### New Project (Return:Project) proj = newProject(name::String, folder::String) The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). -### Opening an existing project file +#### Opening an existing project file (Return:Project) proj = openProject(fileName::String, folder::String) -### Saving a project +#### Saving a project saveProject(proj::Project) writes a control file to the folder designated when creating the new project. It can be read in again with OpenProject. -# Plotting +### Plotting -### Plotting a Project +#### Plotting a Project plotProject(proj::Project, options) @@ -193,22 +198,22 @@ If the model is modified and you want to re-plot with the new values, invoke but genrally the plot will be updated automatically as you build the model. -# Modifying/Editing a Project +### Modifying/Editing a Project -### Setting the name of a project +#### Setting the name of a project The project name is the name under which the mesh, plot, statistics and control files will be written. setName!(proj::Project,name::String) -### Getting the current name of a Project +#### Getting the current name of a Project [Return:String] getName(proj::Project) -# Controlling the Mesh Generation Process +### Controlling the Mesh Generation Process -### Editing the Run Parameters +#### Editing the Run Parameters The run parameters can be enquired and set with these getter/setter pairs: @@ -221,7 +226,7 @@ The run parameters can be enquired and set with these getter/setter pairs: The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite elemnt represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** -### Changing the output file names +#### Changing the output file names By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with @@ -230,7 +235,7 @@ By default, the mesh, plot and stats files will be written with the name and pat [Return:nothing] setFolder!(proj::Project,folder::String) [Return:String] getFolder(proj::Project) -### Adding the background grid +#### Adding the background grid There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. @@ -240,7 +245,7 @@ There are three forms for the background grid definition, one for when there is Use one of the first two if there is no outer boundary. With the first, a rectangular outer boundary will be created of extent [x0[1], x0[1]+N dx[1]]X[x0[2], x0[2]+N*dx[2]]. The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. The arrays `x0`, `dx`, `N`, `bgSize` are all vectors [ *, \*, \*] giving the x, y, and z components. -### Smoothing Operations +#### Smoothing Operations A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. @@ -259,7 +264,7 @@ To remove the smoother altogether, [Return:nothing] removeSpringSmoother!(proj::Project) -### Manual Refinement +#### Manual Refinement Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. @@ -314,9 +319,9 @@ To further edit a `RefinementLine`, use the methods [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) -# Boundary Curves +### Boundary Curves -### Adding Outer and Inner Boundaries +#### Adding and Removing Outer and Inner Boundaries - Adding an outer boundary curve @@ -354,7 +359,7 @@ To edit curves they can be accessed by name: [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) Generic: remove!(...) -## Defining Curves +#### Defining Curves Four curve types can be added to the outer and inner boundary curve chains. They are @@ -364,7 +369,7 @@ Four curve types can be added to the outer and inner boundary curve chains. They - spline -### Parametric Equations +##### Parametric Equations - Creating new @@ -386,7 +391,7 @@ Four curve types can be added to the outer and inner boundary curve chains. They The z-Equation is optional, but for now must define zero for z. -### Line Defined by End Points +##### Line Defined by End Points [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, xStart::Array{Float64}, @@ -398,7 +403,7 @@ The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should Example: cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) -### Circular Arc +##### Circular Arc [Return:Dict{String,Any}] newCircularArcCurve(name::String, center::Array{Float64}, @@ -414,7 +419,7 @@ Example: iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") -### Spline Curve +##### Spline Curve A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. @@ -438,7 +443,7 @@ or by constructing the Nx4 array supplying it to the new procedure. The construc If the curve is to be closed. The last point must be the same as the first. -## Editing Curves +#### Editing Curves You can determine the type of a curve by @@ -476,7 +481,7 @@ Otherwise there are special functions to change the parameters of curves [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) [Return:Float64] getArcRadius(arc::Dict{String,Any}) -## Undo/Redo +### Undo/Redo The HQMTool has unlimited undo/redo for most actions. @@ -496,6 +501,6 @@ Finally, to clear the undo stack, use [Return:nothing] clearUndoRedo() -# Advanced +## Advanced -All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file +All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. diff --git a/HQMTool/Demo/AllFeatures.control b/examples/AllFeatures.control similarity index 100% rename from HQMTool/Demo/AllFeatures.control rename to examples/AllFeatures.control diff --git a/HQMTool/Source/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl similarity index 100% rename from HQMTool/Source/ControlFile/ControlFileOperations.jl rename to src/ControlFile/ControlFileOperations.jl diff --git a/HQMTool/Source/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl similarity index 100% rename from HQMTool/Source/Curves/CurveOperations.jl rename to src/Curves/CurveOperations.jl diff --git a/HQMTool/Source/Curves/Spline.jl b/src/Curves/Spline.jl similarity index 100% rename from HQMTool/Source/Curves/Spline.jl rename to src/Curves/Spline.jl diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 48d8fbe5..bc9c8314 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -1,10 +1,22 @@ module HOHQMesh -import HOHQMesh_jll +# Include other packages that are used in HOHQMesh +# (standard library packages first, other packages next, all of them sorted alphabetically) + +using HOHQMesh_jll: HOHQMesh_jll +using Requires: @require export generate_mesh +function __init__() + # Enable features that depend on the availability of the Makie package + @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin + using .Makie + end +end + + """ generate_mesh(control_file; output_directory="out", @@ -89,4 +101,7 @@ Return the path to the directory with some example mesh setups. examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") +# FIXME: Include this in a proper way +include("HQMTool.jl") + end # module diff --git a/HQMTool/HQMTool.jl b/src/HQMTool.jl similarity index 86% rename from HQMTool/HQMTool.jl rename to src/HQMTool.jl index 7d890306..f8086493 100644 --- a/HQMTool/HQMTool.jl +++ b/src/HQMTool.jl @@ -24,24 +24,22 @@ --- End License =# -using Base: CyclePadding, Int64, Float64, current_logger, parseint_preamble, String, Bool using Printf -using HOHQMesh #= A program for reading, writing and plotting a model for HOHQMesh =# -include("Source/Viz/VizMesh.jl") -include("Source/Misc/NotificationCenter.jl") -include("Source/Misc/DictionaryOperations.jl") -include("Source/Curves/Spline.jl") -include("Source/ControlFile/ControlFileOperations.jl") -include("Source/Curves/CurveOperations.jl") -include("Source/Project/Project.jl") -include("Source/Project/CurvesAPI.jl") -include("Source/Viz/VizProject.jl") -include("Source/Project/Undo.jl") -include("Source/Mesh/Meshing.jl") -include("Source/Project/Generics.jl") +include("Viz/VizMesh.jl") +include("Misc/NotificationCenter.jl") +include("Misc/DictionaryOperations.jl") +include("Curves/Spline.jl") +include("ControlFile/ControlFileOperations.jl") +include("Curves/CurveOperations.jl") +include("Project/Project.jl") +include("Project/CurvesAPI.jl") +include("Viz/VizProject.jl") +include("Project/Undo.jl") +include("Mesh/Meshing.jl") +include("Project/Generics.jl") # #---------------- FOR TESTING PURPOSES -------------------------------------- @@ -52,7 +50,7 @@ function runDemo() Reads in an existing control file, plots the boundary curves and generates a mesh. =# - p = openProject("AllFeatures.control", "Demo") + p = openProject("AllFeatures.control", joinpath(@__DIR__, "..", "examples")) plotProject!(p,MODEL+REFINEMENTS+GRID) println("Hit any key to continue and generate the mesh") readline() diff --git a/HQMTool/Source/Mesh/Meshing.jl b/src/Mesh/Meshing.jl similarity index 100% rename from HQMTool/Source/Mesh/Meshing.jl rename to src/Mesh/Meshing.jl diff --git a/HQMTool/Source/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl similarity index 100% rename from HQMTool/Source/Misc/DictionaryOperations.jl rename to src/Misc/DictionaryOperations.jl diff --git a/HQMTool/Source/Misc/NotificationCenter.jl b/src/Misc/NotificationCenter.jl similarity index 100% rename from HQMTool/Source/Misc/NotificationCenter.jl rename to src/Misc/NotificationCenter.jl diff --git a/HQMTool/Source/Model/Geometry.jl b/src/Model/Geometry.jl similarity index 100% rename from HQMTool/Source/Model/Geometry.jl rename to src/Model/Geometry.jl diff --git a/HQMTool/Source/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl similarity index 100% rename from HQMTool/Source/Project/BackgroundGridAPI.jl rename to src/Project/BackgroundGridAPI.jl diff --git a/HQMTool/Source/Project/ControlInputAPI.jl b/src/Project/ControlInputAPI.jl similarity index 100% rename from HQMTool/Source/Project/ControlInputAPI.jl rename to src/Project/ControlInputAPI.jl diff --git a/HQMTool/Source/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl similarity index 100% rename from HQMTool/Source/Project/CurvesAPI.jl rename to src/Project/CurvesAPI.jl diff --git a/HQMTool/Source/Project/Generics.jl b/src/Project/Generics.jl similarity index 100% rename from HQMTool/Source/Project/Generics.jl rename to src/Project/Generics.jl diff --git a/HQMTool/Source/Project/ModelAPI.jl b/src/Project/ModelAPI.jl similarity index 100% rename from HQMTool/Source/Project/ModelAPI.jl rename to src/Project/ModelAPI.jl diff --git a/HQMTool/Source/Project/Project.jl b/src/Project/Project.jl similarity index 100% rename from HQMTool/Source/Project/Project.jl rename to src/Project/Project.jl diff --git a/HQMTool/Source/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl similarity index 100% rename from HQMTool/Source/Project/RefinementRegionsAPI.jl rename to src/Project/RefinementRegionsAPI.jl diff --git a/HQMTool/Source/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl similarity index 100% rename from HQMTool/Source/Project/RunParametersAPI.jl rename to src/Project/RunParametersAPI.jl diff --git a/HQMTool/Source/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl similarity index 100% rename from HQMTool/Source/Project/SmootherAPI.jl rename to src/Project/SmootherAPI.jl diff --git a/HQMTool/Source/Project/Undo.jl b/src/Project/Undo.jl similarity index 100% rename from HQMTool/Source/Project/Undo.jl rename to src/Project/Undo.jl diff --git a/HQMTool/Source/Viz/VizMesh.jl b/src/Viz/VizMesh.jl similarity index 100% rename from HQMTool/Source/Viz/VizMesh.jl rename to src/Viz/VizMesh.jl diff --git a/HQMTool/Source/Viz/VizProject.jl b/src/Viz/VizProject.jl similarity index 99% rename from HQMTool/Source/Viz/VizProject.jl rename to src/Viz/VizProject.jl index 8104037e..b557d035 100644 --- a/HQMTool/Source/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -24,8 +24,6 @@ --- End License =# -using GLMakie - const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 const REFINEMENTS = 8; const ALL = 15 """ From 47d0152021ee3f6549d5c3de0891af0dc94072ad Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 1 Mar 2022 13:23:15 -0800 Subject: [PATCH 003/164] Add source and docs --- HQMTool/Doc/CheatSheet.md | 64 +++ HQMTool/Doc/HQMTool.md | 501 ++++++++++++++++++ HQMTool/Doc/iceCreamCone.png | Bin 0 -> 436345 bytes HQMTool/HQMTool.jl | 143 +++++ .../ControlFile/ControlFileOperations.jl | 316 +++++++++++ HQMTool/Source/Curves/CurveOperations.jl | 243 +++++++++ HQMTool/Source/Curves/Spline.jl | 131 +++++ HQMTool/Source/Mesh/Meshing.jl | 53 ++ HQMTool/Source/Misc/DictionaryOperations.jl | 89 ++++ HQMTool/Source/Misc/NotificationCenter.jl | 107 ++++ HQMTool/Source/Model/Geometry.jl | 93 ++++ HQMTool/Source/Project/BackgroundGridAPI.jl | 265 +++++++++ HQMTool/Source/Project/ControlInputAPI.jl | 60 +++ HQMTool/Source/Project/CurvesAPI.jl | 450 ++++++++++++++++ HQMTool/Source/Project/Generics.jl | 164 ++++++ HQMTool/Source/Project/ModelAPI.jl | 427 +++++++++++++++ HQMTool/Source/Project/Project.jl | 409 ++++++++++++++ .../Source/Project/RefinementRegionsAPI.jl | 476 +++++++++++++++++ HQMTool/Source/Project/RunParametersAPI.jl | 190 +++++++ HQMTool/Source/Project/SmootherAPI.jl | 118 +++++ HQMTool/Source/Project/Undo.jl | 142 +++++ HQMTool/Source/Viz/VizMesh.jl | 78 +++ HQMTool/Source/Viz/VizProject.jl | 194 +++++++ examples/AllFeatures.control | 4 +- 24 files changed, 4715 insertions(+), 2 deletions(-) create mode 100644 HQMTool/Doc/CheatSheet.md create mode 100644 HQMTool/Doc/HQMTool.md create mode 100644 HQMTool/Doc/iceCreamCone.png create mode 100644 HQMTool/HQMTool.jl create mode 100644 HQMTool/Source/ControlFile/ControlFileOperations.jl create mode 100644 HQMTool/Source/Curves/CurveOperations.jl create mode 100644 HQMTool/Source/Curves/Spline.jl create mode 100644 HQMTool/Source/Mesh/Meshing.jl create mode 100644 HQMTool/Source/Misc/DictionaryOperations.jl create mode 100644 HQMTool/Source/Misc/NotificationCenter.jl create mode 100644 HQMTool/Source/Model/Geometry.jl create mode 100644 HQMTool/Source/Project/BackgroundGridAPI.jl create mode 100644 HQMTool/Source/Project/ControlInputAPI.jl create mode 100644 HQMTool/Source/Project/CurvesAPI.jl create mode 100644 HQMTool/Source/Project/Generics.jl create mode 100644 HQMTool/Source/Project/ModelAPI.jl create mode 100644 HQMTool/Source/Project/Project.jl create mode 100644 HQMTool/Source/Project/RefinementRegionsAPI.jl create mode 100644 HQMTool/Source/Project/RunParametersAPI.jl create mode 100644 HQMTool/Source/Project/SmootherAPI.jl create mode 100644 HQMTool/Source/Project/Undo.jl create mode 100644 HQMTool/Source/Viz/VizMesh.jl create mode 100644 HQMTool/Source/Viz/VizProject.jl diff --git a/HQMTool/Doc/CheatSheet.md b/HQMTool/Doc/CheatSheet.md new file mode 100644 index 00000000..05763e8a --- /dev/null +++ b/HQMTool/Doc/CheatSheet.md @@ -0,0 +1,64 @@ +#HQMTool CheatSheet + +Workflow: + +1. Create a project +2. Add boundary curves +4. Add a background grid +3. Add manual refinement (if desired) +5. Generate mesh + +### Project + + p = newProject(,) + +### Plotting + + plotProject!(p,options) + updatePlot!(p,options) + +### Curves + + c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* + c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* + c = new(name, xEqn, yEqn, zEqn ) *Parametric equation* + c = new(name, dataFile) *Spline* + c = new(name, nKnots, knotsMatrix) *also Spline* + +### Manual Refinement + + r = newRefinementCenter(name, center, gridSize, radius ) + r = newRefinementLine(name,type, startPoint, endPoint, gridSize, width ) +### Adding to a Project + + add!(p, c) *Add outer boundary curve* + add!(p, c, ) *add curve to an inner boundary* + add!(p, r) *Add refinement region* + + addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* + addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* + +### Accessing items + + crv = get(p,curveName) *Get a curve in the outer boundary* + crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* + indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* + r = getRefinementRegion(p, name) + +### Removing from Project + + removeOuterboundary!(p) *Entire outer boundary curve* + removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve + remove!(p, name) *Curve in outer boundary* + remove!(p, name, innerBoundaryName) *Curve in inner boundary* + removeRefinementRegion!(p, name) + +### Editing items + +All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. + +### Meshing + + generateMesh(p) + removeMesh!(p) + \ No newline at end of file diff --git a/HQMTool/Doc/HQMTool.md b/HQMTool/Doc/HQMTool.md new file mode 100644 index 00000000..ed747d79 --- /dev/null +++ b/HQMTool/Doc/HQMTool.md @@ -0,0 +1,501 @@ +#HQMTool +HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. + +## Contents + +1. [Introduction](#introduction) +2. [Basic Moves](#basicMoves) +3. [HQMTool API](#API) + 1. [Project Creation and Saving](#Project) + 2. [Plotting](#Plotting) + 3. [Modifying/Editing a Project](#EditingProject) + 4. [Controlling the Mesh Generation Process](#Control) + 1. [Editing the Run Parameters](#RunParameters) + 2. [Changing the output file names](#OutputFiles) + 3. [Adding the background grid](#BackgroundGrid) + 4. [Smoothing Operations](#Smoother) + 5. [Manual Refinement](#ManualRefinement) + 5. [Boundary Curves](#BoundaryCurves) + 1. [Adding and Removing Outer and Inner Boundaries](#AddingCurves) + 2. [Defining Curves](#DefiningCurves) + 3. [Editing Curves](#EditingCurves) + 6. [Undo/Redo](#Undo) +4. [Advanced](#Advanced) + +## Introduction + +HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. +To see that example, run + + runDemo() + +The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The script is + + function iceCreamCone(folder::String) + # + # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, + # written to `path`. This version uses generic versions of + # the API. + # + p = newProject("IceCreamCone",path) + # + # Outer boundary + # + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) + # + # Inner boundary + # + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) # A line + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") # An arc + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) # A line + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") + # + # Set some control RunParameters to overwrite the defaults + # + setPolynomialOrder!(p,4) + setPlotFileFormat!(p,"sem") + # + # To mesh, a background grid is needed + # + addBackgroundGrid!(p, [0.1,0.1,0.0]) + # + # Show the model and grid + # + plotProject!(p, MODEL+GRID) + # + # Generate the mesh and plot + # + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + updatePlot!(p, MODEL+MESH) + + return p + end + +The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. + +To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, if desired. As in HOHQMesh, there are four curve classes currently operational: + +- Parametric equations +- Splines +- Lines defined by their end points +- Circular arcs + +In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. + +Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. + +For convenience, `newProject` will generate default run parameters, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). + +One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extent of the domain to be meshed, so only the mesh size needs to be specified using + + addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + +The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. + +The script finishes by generating the quad mesh and plotting the results, as shown below +![](iceCreamCone.png) It also returns the project so that it can be edited further, if desired. + +To save a control file for HOHQMesh, simply invoke + + saveProject(proj::Project,outFile::String) + +where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. + +Methods are available to edit a model. For example to move the center of the outer boundary + +## Basic Moves + +To create generate a mesh you + +- [Create a project](#newProject) + + p = newProject(,) + +- [Create inner and outer boundary curves](#DefiningCurves) + + c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) + c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) + c = new(, xEqn, yEqn, zEqn ) (Parametric equation) + c = new(, dataFile) (Spline) + c = new(, nKnots, knotsMatrix) (also Spline) + +- [Add curves](#AddingCurves) to build the model to see what you have added, + + add!(p, ) (Add outer boundary curve) + add!(p, , ) (add curve to an inner boundary) + +- To [visualize](#Plotting) the project's model, + + plotProject(p,MODEL) + + To update the plot at any time, use + + updatePlot!(p, options) + + Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) + +- Set the [background grid](#(#BackgroundGrid)) + + addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) + *OR* + addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) + + addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) + +- [Adjust parameters](#RunParameters), if desired (e.g.) + + setPolynomialOrder!(p,order) + +- Generate the mesh + + generateMesh(p) + +The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. + + +#HQMTool API +# Project Creation and Saving + +### New Project + + (Return:Project) proj = newProject(name::String, folder::String) + +The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). + +### Opening an existing project file + + (Return:Project) proj = openProject(fileName::String, folder::String) + + +### Saving a project + + saveProject(proj::Project) + +writes a control file to the folder designated when creating the new project. It can be read in again with OpenProject. + +# Plotting + +### Plotting a Project + + plotProject(proj::Project, options) + +The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show where [manual refinement](#ManualRefinement) is added. + +If the model is modified and you want to re-plot with the new values, invoke + + updatePlot!(proj::Project, options) + +but genrally the plot will be updated automatically as you build the model. + + +# Modifying/Editing a Project + +### Setting the name of a project + +The project name is the name under which the mesh, plot, statistics and control files will be written. + + setName!(proj::Project,name::String) + + +### Getting the current name of a Project + + [Return:String] getName(proj::Project) + +# Controlling the Mesh Generation Process + +### Editing the Run Parameters + +The run parameters can be enquired and set with these getter/setter pairs: + + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) + [Return:Int] getPolynomialOrder(proj::Project) + [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) + [Return:String] getMeshFileFormat(proj::Project) + [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) + [Return:String] getPlotFileFormat(proj::Project) + +The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** + +### Changing the output file names + +By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with + + [Return:nothing] setName!(proj::Project,name::String) + [Return:String] getName(proj::Project) + [Return:nothing] setFolder!(proj::Project,folder::String) + [Return:String] getFolder(proj::Project) + +### Adding the background grid + +There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. + + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + +Use one of the first two if there is no outer boundary. With the first, a rectangular outer boundary will be created of extent [x0[1], x0[1]+N dx[1]]X[x0[2], x0[2]+N*dx[2]]. The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. The arrays `x0`, `dx`, `N`, `bgSize` are all vectors [ *, \*, \*] giving the x, y, and z components. + +### Smoothing Operations + +A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. + +To change the defaults, the smoother parameters can be set/enquired with the functions + + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) + [Return:String] getSmoothingStatus(proj::Project) + [Return:nothing] setSmoothingType!(proj::Project, type::String) + [Return:String] getSmoothingType(proj::Project) + [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) + [Return:Int] getSmoothingIterations(proj::Project) + +`status` is either "ON" or "OFF". + +To remove the smoother altogether, + + [Return:nothing] removeSpringSmoother!(proj::Project) + +### Manual Refinement + +Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. + +To create a refinement center, + + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, + x0::Array{Float64}, h::Float64, + w::Float64 ) + +where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. + +Similarly, one can create a `RefinementLine`, + + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64 ) + +where `x0` is the start postition and `x1` is the end of the line. + +To add a refinement region to the project, + + [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) + +To get the indx'th refinement region from the project, or to get + a refinement region with a given name, use + + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) + +Finally, to get a list of all the refinement regions, + + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) + +A refinement region can be edited by using the following + + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) + [Return:String] getRefinementType(r::Dict{String,Any}) + [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) + [Return:nothing] setRefinementGridSize!(r::Dict{String,Any},h::Float64) + [Return:float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) + [Return:float64] getRefinementWidth(r::Dict{String,Any}) + +where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. + +To further edit a `RefinementLine`, use the methods + + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) + [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) + +# Boundary Curves + +### Adding Outer and Inner Boundaries + +- Adding an outer boundary curve + + Using the curve creation routines, described in the next section below, create curves in sucessive order counter-clockwise along the outer boundary and add them to the outer boundary curve using + + [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + Generic: add!(...) + + `crv` is the dictionary that represents the curve. + +Example: + + add!(p,circ) + +- Adding an inner boundary curve + + [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + Generic: add!(...) + +Example: + + add!(p,cone1,"IceCreamCone") + +To edit curves they can be accessed by name: + + [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + Generic: get(...) + [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) + Generic: get(...) + +- Deleting boundary curves + + [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) + Generic: remove!(...) + [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + Generic: remove!(...) + +## Defining Curves + +Four curve types can be added to the outer and inner boundary curve chains. They are + +- parametricEquation +- endPointsLine +- circularArc +- spline + + +### Parametric Equations + +- Creating new + + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + Generic: new(...) + + Returns a new parametric equation. Equations must be of the form + + () = ... + + The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. + + Example: + + x(s) = 2.0 + 3*cos(2*pi*s)^2 + + The z-Equation is optional, but for now must define zero for z. + +### Line Defined by End Points + + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + Generic: new(...) + +The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should be zero and for now is ignored. + +Example: + + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) +### Circular Arc + + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) + Generic: new(...) + + The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". + +Example: + + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + +### Spline Curve + +A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. + + 9 + 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 + 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 + 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 + 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 + 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 + 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 + 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 + 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 + 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 + +or by constructing the Nx4 array supplying it to the new procedure. The constructors are + + [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + Generic: new(...) + [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) + Generic: new(...) + +If the curve is to be closed. The last point must be the same as the first. + +## Editing Curves + +You can determine the type of a curve by + + [Return:String] getCurveType(crv::Dict{String,Any}) + +For any of the curves, their name can be changed by + + setCurveName!(crv::Dict{String,Any}, name::String) + +and checked by + + getCurveName(crv::Dict{String,Any}) + +Otherwise there are special functions to change the parameters of curves + + [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) + [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + [Return:String] getXEqn(crv::Dict{String,Any}) + [Return:String] getYEqn(crv::Dict{String,Any}) + [Return:String] getZEqn(crv::Dict{String,Any}) + [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) + [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) + [Return:String] getArcUnits(arc::Dict{String,Any}) + [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) + [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) + [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) + [Return:Float64] getArcRadius(arc::Dict{String,Any}) + +## Undo/Redo + +The HQMTool has unlimited undo/redo for most actions. + +In interactive mode, actions can be undone by the commands + + [Return:String] undo() + [Return:String] redo() + +where the return string contains the name of the action performed. + +To find out what the next actions are, use + + [Return:String] undoName() + [Return:String] redoName() + +Finally, to clear the undo stack, use + + [Return:nothing] clearUndoRedo() + +# Advanced + +All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file diff --git a/HQMTool/Doc/iceCreamCone.png b/HQMTool/Doc/iceCreamCone.png new file mode 100644 index 0000000000000000000000000000000000000000..23511d2bc9342e0490b3c8cc01e6e67019f3b48f GIT binary patch literal 436345 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

(R3ztIK~x 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üq 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%0Dr(21&z%>XKL|t4bbV$aAGv@ z$O3rt%RH$q?zM{{Xl(8KMuhDZAB2*!<^)0Q z6T+iMlI^tII(9XyI?SqRb=v5plLIS9gaa$3(#_XY!oGb&?*$-A|Ze|xW0 zD!)UX*N<7WGvIkGU8J^>>CF^i-F9;xWIgO=o@B#0L~%#(Y;mT)6p)qmb}?Q3bOI(zL!?$zPCKEaCH=pa z1xAyVBu#~R-hY&nRUBQ{Ec;q@{|%z;i}5P^@VsJ_@)C$S@IS1r2g+EDnh=J z6NX}AW6E$x9GBv>c6`pbL-LCBpz_e7uD)(!d)4W&M;z%far#q_3u(LXuBVYrn|6>- zfzfKNiU5-Nxk*(HU#mhaLn|;R^BQ2d2LomMW{Mrdm^xLtK$+6lmf+b{sIUvk9hTs- z1T2kpqTx>HxvcQ2CFTebEZ>NHgzQ8Ep{rATd~Lg>7+dyC=8Ou@ou;qKU5HawPc8+W z&hHrYf47km61$ybps@4DYh&PsI|HT(4g%{VnF14MJl9A?>Jljn-LhlUi!vUx96h88 zp4$u_g_f*(_DHe-?rcT`b=uUY;&VxR*$(aZG_IToEP4^~^(?1vo6GiE*NubH=|Ut{ z`1N#yI%aBK9Qi$LX9!CttX)CbMLWCbd4K+L@2NCVH{ zdQD3O<`>Vm>X1$+T`&!!G&S+)Ng(Nt8!_q+{?3s#uh?(ypi|%UpXh#1nhbQ4 zB`zPpN23x!&{GHEA#fLk^VQIbRer5Aim(xFH>=uYXw5O9vgaxuK>Wc%v*>GvXE}en zZ+dpabuKJdgF1VILf>yp)CacMl}tI}@vQ-iKAU&hYfZKUxfIw(qW8`k=E|b25h!$5 z#9V3XS3N5lo1TjI;i(H_F;cm`sVQ%NrY4LpEy0$C?WSe7Of7 zbZ6jw-%C!3!GKrP5nx0D!7UN8nc(Az62l;PG${?Hrv z&?eyVmuz_;CLFXH*t!c|_2u&j4b0ETidz1TeUUzTl6xt(aQ`xu@kDeGC4ZznLiR}X z)3J7Q^E(-vqkr;Q;G&}&JKK86&L1PwtwS2j7Hh=V6_WflPCyM<^@4B@u9c-z<_W0; zJ|R&y-mLg1go9(Fn@?zQ#%C<;dt(*W-9uli zoEx;2^AOa<~CzanS#~^rnB~T?{d~uGmI}YS-fM zyD*x(wH^x5!t#oCxd}OUQ?C4(F@2q<1QO8eJ5Hr$?xY za~4Cp|C+~+Fe+phAM8k4fhRzxbmy^~3tqLQ#0A~$?IKJztQ8mFNlz2vzLim16)?M) zOKj?^$3`fLhNzq3#wxHL*odm^)o8O|VrA~doDSO{Zd*LeIQFqEjCrecdhac@v0qO- zTz|T$I%FwE!~9(0%t#$LjK2ku_SX%B)*K0|XQ4L!=@2!LqrVc&LGjXgfE<%FRklXp ztLyN?XP;X#m76n|9439XoT(uJw3>J-AUVM#D6af8pARfd+MO>--{LF&V}8KIzREPV_1E{$w#bBM$Pb& zM_Ppc$yy6*cq}<2SNo{h1Lkaxz@`es#uZx$68!$~td#*G+D3HbQp?E`sH-`=X&lY* z$wbZZY1(;mo6gNYU(B)9Ja%}I((0n}T`GjVyN6|v8aHI6@)Lw?3sjElE;`ERrXwiK z<>iEN@rg4~%5c4GD1Ptv1hs_D24n_x(PQ0;tbA$qfh2`sy@9Lw&9vT7Xj=1sPGP=P zn<>O<7c}9x1M3WBT&%yy8*uXvxHZXY0x5$}1Ma`c+6Gx&Rv1^YL_!em-3GtzBL4dX z+N*IjBX95~3&mSYvDZ=eh~rFeq6FP_`&Y3)XP^jK8leJ!QD1nh*(#llyvD2c|ZX#veGQOCQedcBIawU)h}Jn>&obOV;?BL zbI-VI_SHzd2;%M^VK~Uo6QJ!s%FRw|{kAi9HMCd*%U6B`-@Q4PA2s4w?9^CSF6k!VJS;^sT7(Y$cb#R(`4ZrWR~e@3sb zu;-Iu8Q2P|&j_gy=FAP)PVQA91SgK=y?$lQlW)`tb z&8MOtXLb5is~fS}pRV}ZI!-CdaEbT6iHwj`?;YS1D?gtvxCb~Xsb)yIS1FoXs4ds~ zFAy>0CyQ?v#ml~LppqTS;d~DK?bRyuYv>p(Np1&f zd2mCl7oZ9%v&KZY>ug|;hJzQfH2p_~RQUnCIv@J$Py12d? zKCl2=3c%Jegl0abH}D#R>%Y%!gx_RtufYn!rQOib3cZ*&i3E0;%{Q2B)q8{t1lSTk zA@X9nAZZXaPz)-RTiH}2;2h0{=?7l_d8$__)45J&?6ko%keG2Wj4-Cwy_7SjgI!1Z^1q^-`3cy9mV<==bIQoMDQ}Z+yFsVW_k{L}u3t#khC<@=_D_ZN0xu2ll+DEEBhdGfAgcWP^ z3sQyOC0QPqC0?_ctz&OBr8 zV78y*@k!_n)XvRR9o94_lw5?zJf4&oX1D7-;--<)QoSvReWGbn$XYSWB>cHv-HvSds+-XJ&)-D1^@JW*!|LF-ErJNx7etc z$y4{0$X+Ne=v3E+`^(#!hj_0Gs7sPE5C-+i05B~LvRl4I`xqq&nC6=x}F5DwlmzYFStd(O^)Jon|| zX}zuyk*i~R)Is;lX;&TnFq?*m9|3gjqy9gb<^C?ku6$5xoxb@?l^k(Z!trDi?7{sQ zw2MAcB5!o^Lz~?_zVMv&_1#ZYj|Oj~A_!O6VRqBtC%wq;=fDlTXA;ATB26RPFD$=D z85)Sx(?_6jYv|^8FJJOudKCe1^%&UIAdrVhdtg-F;>a&*{{lOnIBitA!~18i_g!|6q#2? zu%cDFPoK*64|8q`%*Z=LErRd)=GrWy!e8E(JbIE)xZuZRbk3G8fAD)Mu#B2?<*NuC zN&@V3(;L+0Rg&fXpXo}!PFQ{k1Zc569&o#lvCKoS5S89Z7zYH6%ECrQ#h&3o_T{b$ z3?ARwKzAp*59{7x0Ge8)`|n}CLO|0v%|gmylu;L!e23nV_%mq5m&~`&HLESt+l|WD ziQB4I0>H13hgV z!-95ebSMeUy<~33aM_P8+XK%gpa+eMmtBkp&x3s zBpx6!rTe>?k(+@TNLXuJXZ2x7-uL6`Jew4$6o2o1W(T{&7CthB^ED`7v5hhFE!H17 z2SXXU$All{$EgGH<`!H+G>xY48$?;>A`n9i!M%Sgxrwc>V$PyuKhT!-x zZK|zqs2UQHVruN|h@j z>}(2p^?`rOV;tX?)QnHbAJGCkZI^&^?YcMbIBBWS)RK8>bu3X7nn+*H?AtamSkbSU z&)V2v%kP}3{V}J8c5r9A!_f+3C$`}vFxJVq_u}AEn$a;u#=KRML_*M zEF4xS8>T!+cx(LCtb&|f;V}!`(hEB%MzP3MF0s#mOX{4~8cuaxEDhy`N@2_M#}x!NzCiUImOVkub*+%A$ho% z#=0%}6}OTK4aIOS868GL?1TjOBXZ|aV{EA9DNw;rC04GoGEJTq?@L_jas{D~QbLmp z`h}-KMjhEH|J#&UuTnh%QpYrOe>;C^FFNQ7*mM;^(RrYzu`mW`s|&vIfcLlSX6>N; zOPbnY162Gb>Fvbj1}b^ zSbeVzBR^=9*&uBY@>rrWv1Z#yx$HK8qM^y48IpOhGaJW80HOtCAm*oCc~R&S;T4fA zJ=&wAn2{W5pnLp7)*DB5F!ZE|{a6lC)2Ey4WCADNLwy0N=0_c%4OVKY@z=YeJ3v@2 zC=$X*iAoHi<9Zwp1hH|hhfvX1_*6NxZ~b|R1n{`-q~ zKW#F{-ub#t!4Jo%?>@$5h#f2#9>rx7~U5aw~+GEz z%xtCEg!Yx5Q+cMb%HrjL$D7y>sEQP+W~CIhWu{N@uD4mLC!#ilx65&IriXua9xY)2NrthY$_w)GV0yK+PtAg+?uoX2y_T5t<`8FXaWw1;a4#OCR`7~NR0ROg zXir3vV`rwwW;0=}}#3)I;}hW3H=YPd%{l3)9^W#=;Xx z;`qNVlf1I{mso@5sN#V+MOwPkOi62OyBGK}oi}~9*AHO zg($L|QkSZl?jAy0vUw^KCsjHl5yglw2|)6p2P*iLFFmPX=~?!n;q1r>o57NR)}W@a zb3kttfq3pUqiVq%$Vi*pM2s_v&-;IW{Ev`)m}+*Oi@FYg1sqr{Lw2s>76EEP$Ke^( zIDw-O_N}@Bo^wii!zoNh(^<(ZB}B49yX)mi`UFU|{l!yCX;VsYnN?}u=zcq=@%sDn zF>RM(4kA(B-30cJ*XY59)15kuwT>1rd$#zHr2l+mPu1Bot9d1&!$Op4l;i8mvzXN( z%vZy9QyXDwF7r(PN9u$>LbJD|&kn|nJ$v;0#?3+#vv2eZ{xX6urc+h#f&Qun$*q`8 zTlattrpJ@Xn|tvnhHZPIr8W)CS0(d*R;XuP{z-{!Pi&>&=G~Xr%&f|9D{+c__8R;> z&E_RYxr<$uT9z>eSvP-x-TsjtcKo>T`Z9BRJ#n-lV+$l-%BA<9qs=R|G4MJ>1P{(j zifACG!|$1mr8TFv&=Y?1Jyh@qtVoI_2Yy?teBO|&79x~B(pF5ih;ZjEuaFY)ZReLU z0c1tD8`q_Ul;iw0=ZtkvP9Bdg_<>*euDSy@r%5IUf8#|@%S%&uik$?_x&c{d%<8~b z4t(7(15Mpdlog}dkE+b&z_TI69ZH=4SP>p{w<;yIvhhMe1j91g$0{E7y6BJ z5x5|6k;xlD7etR2&Z((NVG1csbm<1{af;)EcHT?`0^=@KWV#sc)x~4I%b&TuEaqBS z+LNhTdL!{ij*;JolJUJ$O#sj{UsfR{PLHkFpHtKfhbZpeqdhYE*63TDvuS<(f~nd1^Br?V zux#1}AiGTSPcN^ZUG2!>0m0&Dt;=*1?96=jE5?>n`6NHme%x-I>(gJAF4Omin8h3e ztR%5AtR34X;VP@Ke$jcaF$4)2r@SO$q7kN?j(3>`?!A()CKZxDV?ScoP8Z+Azxlxl z0g%QT5>E~!d;cE9s*ciW#A$HGebvoEQAKph>OJEBiCJrQ)7CSfpf>!&@EfUUWlf7w zwZaBP%_vQB+ifF7iqrm2Q1JkcSPYQSDkEUVGO-&=S4cIVPXdCs_>6y8>yX{VxUV?u zNRu_9w)nr`uU+h<m+s%`N22WSe(tSXW!8wN)#vmElT>4B@ zp~I`}C)`;(E;VyG-?3cKkWg^(7R|;B;>6JFH!E%kNDFZ|gbGgYfR~A7$yJ}k>`k4`z3qAw&v}JN5V;v*)v>_4ov^(GS_ylneZn|NIX>9}nTFq%~ zHNEE=m@&)5igScAp{2PIO4XGzvab0JaA}z02H37H$xa%2R{;(Xf#6R!%P@@HCagxvYGc z8&d&=P{62CWJzgLGyY!k_0r9%Tgg1lCm`P{0(!8{1z2X#(yh0j{aWnEkf5u=|FK_J z7j_jx7%Qt(eA(M#ky&6%%GaA9#*`ReMG> z-TA||B%!I8|E)qyTjdWe%VV|*H{Z0gxc<;dE{*P^8*Vlf|JwV@f#fz!;kR+Mx>F61XD4|Xz?arEuMXNA!{2%(+ME*grzC1U0>(x_@#H6T+os6XbdYM zlRtZ?9q4l@=4^5Qk(+A*J4#&GS}JuQC2%8n!U|NxI1)Ao!489Y3#l9PdT3 zud-J$K6{K(SJ$5^z%}Yye^zs<7Hw}A8F_OHZSWobv$+CW={q}s3EE345cpM(!JfMU ze9HcD5^ml5Np{&G^r>bqWi}q15>NiGT4e~=PSpXBz5q9#g;7vSyIG=LCjQ8) zJq1wOP!F~^@a3E@5D6{PC(+xux+HEm;cLDMYUOCd-eJoSfg3UDRe!S znj|g1BK}#J@{vy>`nVhKaaR~@nzr&KHK4fvFh-;&2>S@i83@F1Z1-jO@vceWJl~a| za<(J#J#KfjWGA!%kmShug?ApOOKI2C`ObaqmCTaSq+4&yrEWochKC%m!S4t96|i-R zi-r$5#JTw^6TLT*o1aukHUtLD5K3VA`$ZN_@ezWAu+r zcrouyx&4Rp!7s&EO8jyzC-vF~T>@4^qqT?+V$htnyp9=dc2RV@W!VktjbZ?JGka znp2l_&jS1Q@_=Tk_B=iMtR!qX20&wS##RiNrSL)>B1{8%lN8UjN^E%8gp?U>n;HI> z-81XeK3|WYe6r@3Vb&P=r96nu1)kbu}j zZ1i8||5%mDjfIu*O>Q9jA(4MQSWkX5w~!lYgoU@t{`Fav0otw?#H^_%m!4oPI=x&_ zxC6!e8e9N>B1uT&mKeAow%vq3&oMsoOxZmjwW_pOWtsYTjNfl>W()49JyynWwN}>I z3B&yuAa>L=9Dsmi^=R`6wYf0WVd8(%6Kh7B88AJ4Asks{t(mU|1f-cIM}L8?F&F$1 z;ZG_aQ9uvVQDeFv`+zE~7}?^71ZRb;oe$<#S?k5P#2FZ&YB~<7at?+)TY8paB%kW9 zp*cO}>`hk$h~i@Y?d_Veghee}gGFc>g>={DDO&o=gKP&7y!F0;~NYPjk-KPN6Wo)0rWN1#C#+_#eK?g~GE7zqUCMny*h`w_b7 z(j&a7Aow<&W4GEbl2K}*cq_8_!bT&KFnqDp(Ynz}>QimOvVGmru@;hHD4L5EMWi0< zdi$RzHV~|n4+v_r-XsvJHmUMtb7RafNYCG;SFLl7B8ub9Q3+bGWs=Jw8J+Y%Bd_Bg zoA*@EASdqybKHxrj4#^&PM^4^Z4`uH^i`a~-K4ZL#o-;C^K8Vs*UZQlos>||&F?sS zp-Gh(4ihoZ-C5rte;j5k()0*r*;yCUo3K6{a$ias6Da$4DYT-tVh=ZgC^e#puj5;KR zEz<7oXl_c%)IH~%${Ie0X)eDS;3!cLRsRmHlVJAYB&4}^hTQ0%6z|%5Caj*H#+}{p za?C1jUlRb}-R9P)@uy1PRR%tCE-^SGi97g^QqT1e%jeecp2f!}jLs79ZrCH^lEm{E zm0_e%Lk#rl%~t1Z$JoA(p7Xen2Nw#4+FdFYuyv4xA-HK3ze|QmF3>PEGG zr|8P;In^OnsY&^@9kaoT&6P+sL|@w>9AymKoQ~oq9(CS( z9cm_pTzs;an<1XLa!z+dmQYJd@`U@Xm>5Z$)MLMC z=ZP;>rg;X!LqPhzN*V1TE0|jD+ zflD@0@&Zsn$zb#K>S6nBnaC^r+r+c?UI21dnBC#8Q2M4)tKdkj@;K_^}$R zoDPi*_wsREU(I3PltY1nnK+ttT^mj4&l4i@xR=Rb$31oT1dyX9p}#0M-Y%!_M5H@# zeJ*?fN&qw_S$z0S;cb&oCVGWal}KNr^~#p(`ATZA3b60OEt=wjE3?*QTU=BP>xzZ} z@Cy#*JVE}`o{(G~Zbd|xv4!)@aJs+I^lQb{*t$57BW~1hygN@px|Y4L+DjTlys$CH z)19?iB0g>r3_q^OFxP7$D;PrE6K3d!Xt;vQx9yjuKm`y@-Jl;YKU*TFoFSkkH(rWh zB^T&X6lVvRws*{8(9xFv%Fq77K#WhqQk_FyLYXvh=;16ZE-}7~dJ&c|R7`>X^Y0=H zn3^OUEZU&NvZcDKEwe2VOd&ne%3|i4^JmOozQ08nrRrF#DwnlosIrnV3Xhm5(Vhf@ z-?dwin`h$UC7=t{@Jgb}Tjp5)G;+RkSV<qUhUjUz6Er73k4G zk_&8aY)GWtAdmYdAEG0C)>=BG!QqxKmce0H$-S&br+?AjnR0y`4ZHlSExl{+g+}wm z-WKVj^F6=jpS6aLjDP5wr{+IxxKtm^2odJq9ta223*2eTr=5ZpoP@wARE^wNAfX*2 zEaKI@=?J}b(J2(@VL2Z+0UG$)`-gPcju`MggQ6y*y*~5Zm$vC}kC1whNSQbcPq5IC2}D z&XHmPd0FzKzqd0#Ppc{Nv+>nH?n&n`-L;_8lc1aFL3d~kXUY)A+^IRyu8;rnQgd>v zHy8Z78fP8l%L08RhGeUhxa4qb(DzW{oyf}T!E``QzV^r|uk@4?8!qSk)=;8FaW=4lm`3m<% z$PJ66`G_LT7j1ZQN>Lxrg>qIMGvY0_M>b}^&y{FGz>WFO9UQTx?-M{Ht6AwJsW?h(){3v+fY1{ZZZEb6^8=V3@*k7lOr6E3Q)9|b{2g&J4nvixyPB8jS zr)AV<#Q&F$?v~gruX1V>h)N9eV>1$wz3D8k*PE`pExcMuZ-xF3NY3kEivLbEh{>nNe5qJlLM zWVlr5lqAxf^(xFXyy!Uu(F6BKiILLIg(}_*7N}KZnWGd5+A_g@dX#0+-B0?z>u;V~ zJSyR=jMQ6y$3Q)rd%I?X6nDwi0qV#;@UYnVektXMo2(QuEoQaSau2ISUh~Ir-k@A~ z&OM=T;Oc zw6_;Sj!*Z?@IYJXrk*@W(5mfc^b+y@Y$xG;C&x`YRy09#!UoUZOm}6}Y}=E`VP0k^ zWenh4M%+eCQg3FKgg?LoLop!%D3fi$@6qCwLRW$--Z*zJykaT`5^t1XLbg9ovL59e z0Fk|=n(~GE7a@25~v zg01;Y6dyw?#13MEfC=pNZ^WK^H#I!6euXP-K02+b?Yj#=bfQXhG+`A0&vRC zrPDZ@)`$I@!aAoW_)xVAqj$aVjNuhGMiSJ~+QX?^G6tmJ!e{cLI{9w2>N!z_8x9Bv zD+Ns*i>B+3yJ{XTi~NZXzX#*vqze}}y=>>)XiD^4+R0z@JDNRzY{G(8?G`DQ1VKt^ z#zVz%?2}NVW?{?J0lJAj@^YiYOV-YTWEOC0f|x_Ig&F!WP_$v-L5`hi%Id7NMVZ=0gry4iV;jir!eG4%2PX-O z3NW}0ieD8*Oa$YZhv^G7#RwXVKnT`zwWuPA=uH-_;fyH{v3|vpbwfc}kU&p7GH^}W z9F6vv9G$xR$$xk4qiD@y$t`cq1?l?Y3H|79E9NI4le7n%_~{v)WSt0_o2rNJxs8L!nlS6=a;%8)1Hg% z+!?wuzw}f{Rj#6Z6`n1`nYGhyQ3Fo+zDurE}c;#L*l8sg4Kg|WEPB6I=-z~z~ z*b>L%e@>ZlcfWx}2Mg)l!dA+))kM%J4=2|*Gnj45Pv9(q362oSE;htN_(>sD;4k57 zTZ~D!hz^h!oWl7qQ=NvX3u2G1k_vThskuO`fm|ApgTvDr3txgW7D;^8&O@W>W|~GQ z>Ku}G-@-{!iLoTrqk&c5-VlN(W&gSqNgnztKVmT)3jc-BFzx-S<#RR9sSQ*+Tn=?s zB1`7hE_knh@gBgOU*!|F$z`mVnB(2p=)A=p|OQk5ki8&UFnRP$w* zYHg6MyGqj|>N?}6jb0SNHL@oEl=1|t1-5yY*PwO*3FDbiGR);)I=c|bwz!{b_7&K3 zXd5SE0sWPKgzi%J5p!TRQ}3mS%>_+KL-6{%U=q`@@r+z~Gsl0UEuJIT+(Zk)`7Y~y zh4b>CG6`Tf3x0+3B4OR8jKGzK(1izrx%f5&6pS(sJpI;jjbkD`10g8m<+M{r-3ywE zoL#j|<6a!v3c4$f*CD|meE_yWL*T{di{KU4XmI4~J^P{pVYv)T`01bm-Q^%@-tBLn zhAJ&Ez66>;TJkKlJ zKZW!Rv=Y@)s1l*yUeLt=N!UM|&7jO4qxS8oUVIrX5kIG_v-8HH(#QZ3haPPm&Wz-a z>g1{Qp;z_@ufJnve3epbIn|{(Q*l-O!)A|p+H-H&14iGrP!m2HCNeP@WT2oN9+9E7 zyEVg}j@1gyT;5yt)Umq%D5tJ8v1OO8%h7*~7j0h7rp^{i$pki~e%odRc3wwz_3h{5 zNuS$j9Cr2gQVDnGk{)u%5j-N(Ej32~=DM(6kJd`7Nz$xQhtr}DEy)~pQ6#${&ovGn z2T`5n(IPtvLzuM0MFP_$h&NiLCsqU2k$tmJv2|n0ib`XA}X}q^`Y%TnK#~YiC5+T+t9@^cYMvo%tk&<7y#*0{m{)!FE zmQDZ3mW?H4Q35?E|H+n3;gOGt+5Ug}ZGS$TAqKCmaiIB|mgj7%7-r^aB~PTS%?PNN zXaSLv!gg-I$p`Qa{_586PffaBk+zho->7f9-q)@(`c5o(z+=vT35n~FWm)Z7)_|8b zpVyp-lvhe#{Q2^dc$IWU|^G55ry>cGhe z1mX+7#wCQWOkT@&aD(3g(Q}hiYj=((;}u}}%OP~R=NVo;{TvSKQ$jX#;CGgoF{7=S zuKefe!MkVZRK^nVVK+Sct2f`c^$lkr&d0+D#~{a;9A2he8t` zy4BFZaCJkTIdy&I1TmKMR{~cYGGGOH@Etf?*0;?qSlQyEQ&e$cpS&wO1pU=U}$*j@W z0$ZUxu@pIQ*c7TcDWpoc>!?C*z&0O81oJiC zn%h1!*uuw9p~Ta|)shiv%~Zz~&@m}sg!+T?J6&=yw``l8&cCFfX&IJ%Cq%H#kdL(N z@`*?P#f(7vmLtK)w8fYPXei)U(Y1IdtoJ!$H-AdgH|Yz%9!VAZ$$c-L@Lss>edG?7 zZ7I*M#==BN{{ph{M`rrei`dYARB0=+V_CKT*C{o2ZO)A8AKOsVsE4_14hvMBso9Vx zJpRuCkEmCL#g75@G|fdO8TYMOGE2Z~3a>qJHp?pGsY3s(juy4=$rPC5u7l1F$ARO? z;iTHE#E|>qc>{k#%CUFdIeGNoZCCqD706wdMi;TBy39%0OYB|mRSycwwCtr0b--m% zS-kz*k_X+koE_LfY_p)fi)kgjN$FN63 zi+6DakV{=cC@XO)>BlRq&5Y zE|MJ78$9qL{lxK|KX?-)Bs~EkdWimY(@7j0!HI53RcMUcx%V^E=^Ki|EQ68$x1D%} z+F&DLqZu3?S5i2h1Ki?&Hckvh(#CiQQK<~IsGR4dp|ErKoLI#vST|A*)7~A@Ncab* zS|XZEO=%B5tAvoyJDAB8o;%dXnH2_Ga@d1IHKHn*@Cr~FiX9n#7UXE^E=}#b(Bi^^ z3S1HC%QdF9oAa%134K@`7FniG#-YZ&y1W{7vc2oLnscjEXSi)JU6P_A-ku}&$?~PF zJm6j(KKxVJb!1|F9F<6dZV-@>BD`kh)maN+BC=h?kSfpD(w%BU1A{`h5Q3T`)Ic$U zNtuI5F?Z7_f%{xhEbXEj!JF&ykIaMjjO?;eoBc7##7HtJ_?c$Qh9bf#Zp3|{Wd^5y zN*3{i5HzBpT3^T#7yrAif~2UXi!~|2iHImI6xBy+$E3nB?V9_*Eo)*WMn=MC+9}z%4QKPV zYkdbtFD=v-+zs39$J6utWv6oz%pW<8ge(p3LrK4EMh&p+NovH$c?)7W#VY)lTe7+JbBlrb_P}HpS`ybMcJ9#;1-KXB!NjYU?R0>dDh{k@6i(>(PCU z>>tHWI=fDrL@IYIaanDbFuWu;ZsUOmX7U`iQ8)wOwEy^`Bj$WA^s!ah^`0>aTG$m1 z<7kS6vX_Rkwuj+ZT&Nb|HqTS~X6lRcw2Z9~fxy|CPDU9vB^V9-7l@`2A?D3@&3`-E zXe;3?8NgW`Thz;T$3mA=)Qi#XfAx1$a+x`=sK%@@iLP%zm`IvpVA@E41i5tEeiVrB zgvz~ei6px^ipi9Sy8-9KoKuRy^P8o{ElF8T^I2!8E!}9enrBtz#m#Wa_YFW*W}MrS z$N{ECg?yh`Z{I+n!7Xq%hhAs-&SRL06I+W@%mVmM%h2sZ)oj_h&aH)NbsG1v!kEaGv%71O`5PYb$DPwV`y6k>^rZB7ikQjC(Y=_} zPxzgDA?)K}`$M24Hb+1_rj7Vm-i4Uw#I{l?Mxz7vh%f8+o=e(;4r6D*QDdev_HnBS;OA@vU*4`o5IF}*VY-qmJ7F>^P?Ta357 zR87VoUDuZd%PAiPbX1G=$;Z!`$?J!I$=jH6zVF)FnzSB2rojx zyhMIqBihXdoRln4-ty$-#K@SI1$6ywn3yH=lv!Q4%g!UMB%fo$M6C|WYz))nO<5jp zAfOf6sjCqGtVEV{7r#>QP&N8cvCsC=9GtydOO7iM_>f-MV&eFOF#SNl>Ba$c6HJgp z57;ulr(Dwt9I|yRnc?V)@}+cb9k0pvIa+a#mNEaFs#U!`{4*+fXUHzq%JQoH}7c_P7x3XLLreAu;BJ4=RgcNi2`FCd!3! zS+i1ArVjEY{Rv!4TEIKei^+x&_jv)#k7=26^)I!+bgU2KlXZLqTjA39=(m7$g}`$n zi7^mc8>A|m0PQVIREm-!&sQRzOAvG6K*sHef@b>I^~4kpS|iwz()aIYS}I&15V#NKqL~m>?j33iv-1&+ zz@eqwc!Qh6_^{sq2rq3-^U-+*f*dZKx93E*FENh`D$~AA4>OpCW%Ky0-%3v?i?5wZd4FdJWxm&G3#?f3C$r zX7=;Iw&l~-meR8j>JIB+lcKu<%au7Z)n1yc#1c-GmYW8@7Y~^j72H%^6Q!RcX>V|J zRG%D9sFid;Bh0y4Wv(y^&*Yn+eSX5)7$M(jenZ(R5-M**qv z+@ba^z4up`9W^`5yhj>}NEHwYsep9ST9GqA+Qev03^d^!SyTC}#7!t1t2W&d#w|tc zk|i3U<0)+AbohFwu?)t=5LEd=iuvquRy2x+VH(Sa5z)GOjC)97AeW}m1JE*YA-r85 z$f&%`SqH~vmWSI-wQfAKS)SDyw&3E2&=xAwL@;M?V5bFoAQP=ya~(CfbvkN%dYU2? zUv&F#Bxn|hKtE;zhZ{{?o_PJv*^eQ3S!yoJO}i7jJqr-SO2AHJL&qXx7^u2K`Dgt` zN64Fi=Fe{r7ckat7 zQgoljN#f3m+V<>JNrwbEXeFCVe$$)ctPy_HlYq z-9paRPpjw2gihqU4Ud?vi08HC^^w4(%lJ5GoZKs3phte+Np_JLyEDjmH#)fhuc)LO z{}>mtTlMHtjgyy7{0)EM#uSR;J5FNnlGlkzd9^i0A@R%8a45$Iw6bDOex5Q+^ccSa zhgzA$4IwaPyRB+0DE*X^1O6hNxv{EC??4+Tl>X5LTU?Z?YNoT{#q&*B+F-}y68Qb5 zY;~`bA0o6o!N3=jq1kR-jI#CzaH{rqLEJcHc_Hq=grevgsS5e0h%vcn!;tKavWZ5#77jqn(wAQJf0lFu9SavqM}YFbQ%d;cBz>OGU}GNZk~o3_vWne}Bq-oK-=)FZ%01Hc6oPI)pr_yP7^Cz|r%l@M zF9q1MNk*6aFf)uoZZE@n`!T$P+VF$tQa2xf{?u!YJ*?#R6-h4Peo&ET@nOl+P_eD$ z!^b@B{!0F4R9AJ@aq6&F!n?@#!kpK0_8&23;ospU_*A?q?{f>++DF^Gn3u;kxLZ|@ zBxj3m^)88WI-)rc>ME)Gw3~jY-YY}x@c|!}Q$7<5=maQ!1DafeqVgJVwEf6c=#bN* zGq^QX?KH=$@2>h$vqdJ*Z|u3=O%_aPlSY!bULCN2EZ)8TC&8SGX(pOEX@U={q<$l= z@m`YHNlwYSBO^}K1I{#?8Yy!BEWQV)@!w=~>Xtm!vt_71F&odoya{##be!rnarPIS zXwN(5-mA7drKMV4^C`iBT7g;<4ph*b$FcwnPwG)Pa3kR9k8pX)FEB8$>ks^4;2?W~ zpkLNOwC;ETF6Dop?j`otM2oYaG*CC|6i@P z8PNgLi*^>p_2tP6Q*#i;MErIXL$3Vu#AN)qCCz?*+)a8BH%@a+v)PbK+vv9gIzh0U>A z`b9)R4$J+l5o*;u4qJ|5P&$TxayvEEU7IzbQUFrb?lvSKIv6M!@;X~Nzr<--avM~$>E~$j#cDrem)Q#Mdn{}m<~pQ3hzOH9jJcb&%DO1^s;KuUmnps#b=OHaMx2w91gV0CcX9r_R4W+h z$2CZJm0I&bC$NDY05VV0Et%_q?Vl_TUgQ{N7oWT72t*Mmw1g@U7*g?J@;15;w-ZS=<=#k$!DP(VH zO0_UiR*!R@40O<)j-=lp8*!tGrr*4^k8EA`DQs?t$KD)d|FNQ-+Il^!eSsN-Fu05c z@5hm3`HtoB04ap$9g%3H0N2_7KjIccs&RAozMAr}Wy~)oq837V0mw=aeyw{%t&DyJ7`V_%|bqQm2W>8s3JY+w#p8)Cd3A9x3$$y zz*-6dZ;baaLTRZ#88o_2yKR_Wt{6Y-HWI`rKQNmiTwYeZRj-C#91VW0x7BrAWR2bP z+=hMJ-tgR!P%j(@;OH66b=3bF@5tY;lK$EEo;wi8)eL9Ylfb}@HTc7ain8yW-^*8= zk}N}0mCip0atw<>iG1BlTp`%7U?lSg0W|Vu43OT>2lBGr^eu=KrL5=T%Rc+rPy_GQ zTb!x?GzWJG5R;V+3(_fO6T4+En>~!oh{fFMB9{zl&C_r8X2xz}!P+#t|PDntgKu7%{n*a!~gj0oA4-oaS`=dFVA{OvWH>nN^}r<7_Z{IixO z`B|g}Z3}e#oEQ5e3c?9)l=!8uX1Ys-Buq}NkSZnEE$=Ew$Tt`kync#@n zf}RvA(~XOCW27sNK`7TB2;D@-eEg64x-ejqD>>t?e5n>v`+mp0HgQ~Wk7Xr{#CY>k z3$?nT-ZP)08vA(U{&na1sYMgM<4x(lqfM$STXjSVKq;Gi^XMe$7GI(N{!r=XGKlG4 zRIH(NCju0;&2*|j&(mzjmGo-dqJOK8C@L8up1l+vfc(ou4KAMG-e3OLszn9ch(Z<1 z?F$a)wyv}Q?jpt4F3OFRpYk$;9Gj1Za^7+7OnzFi4^7VC>2!7H$~DdeJ6KK%B{YU_ zExf9Uy2roqPyC>^id#(K4c1hl@uw`8foXnv7UEn@(EL+bJmmtm)6Q3=_ZVR<*PPfP zbldDfzdOFcFGTes5e52qOM7^!H|_t825SZF{d63CkNVUxTfAl5a^tUpq-1n3RG&5( z{Az_)FLyPRiz72&i336+#2k{LP2J6Ny;J1?B5W}+$;ZU7n%61Af0|&h%rv6_CoU3D z!qi*tYE{KYVXRdG&^`LwuL%!xEYWJ34DxQ7Qx1qLuzDrOM#kQ;& z$z$;B_U{@(c48%7N%O5pSg1voh%}8|kiez-9fe!dQ*xsHT=NNsstSMw%#J*uFpc>@ z7<3Q$>$W1+TQGOT@JkG>??Y$ccnjPfkQvNKp#G=8?ygZS40B4S0~0aGO0=A2_Q>>l zWn7Nx9B_!JyLtJ%Pi~j!uT^Wq2+7vCa5r;MpXxyY=Amm5P&T-3-I(s9SzZ08)d$=) zXoXtVW5n^ydl2H)X zI;ruA=X2dJX4n-ru=!``J_ zg;h2TW_Bn>KLq~#M5&>c)%&gqI0INo&DcQ*$m((Q<-?$Z!1!r>{m}|l%&ELdgyf>n znvc*Gc{dN%AGChj2`!sLPq7#kkhea|R9jdw!Z~qj2J|ega1kUz9SP6U=8}xFG#$m& z=JF{fOuw|{jgg*eMoYd-))^k|?DnbPidrbK(VvR2mfu`^APK<#fw6f0X-|+4-t|Yg zstZt}Om3@xS7)fkRK?LYpSVVKEj&wq7{-xyKkoB%3-i&w3*sDqrW63k2Jm5HIjIJE zK%fODB^Y(Cra?VEwvSL}pGyCZ(Y2bNuDl(L^>wW0c;Lm`8Vkgc-6lpTKW1d9nuarv}`sS0Jx-VdA-f$alY2U7|4| zBvHvVRE#7-T%xfXz3T63Z4@svgECULwKm0digJl#l2X(wR)eWn^mg?+N4p@?@tl7u zj{fSU8cE2&AAWrKq-+w#@9j$p@f^|Iwu(v^n~f_-=ZA{y<5s#&^FTNFZ^M~ai|URw zQPbi;!WFkkSI_c64#poFVNuT%q}KLb!Avkf-*$|T;@yn{xAPEpK(+I92YgEcarN)X zxUQBxh=+e)&1+Fp-`|B3>bq3*C#yqYsRHq2ZQ#=#LLF-~)0@W`6m_KEu>UF9wauL| zEw3k{Jk+kl@75UxQ$uRjH?RIJ;QArBewnovJzX`HZ8G3F09clPMROYa3F{m|#TIX# z@!$kJO65jDPgs_Cc?KwnOcJwQ#pZhZ@ml^=reG>l1LI&nWjRn2)gd-Zgg4TsZE}fd z^ECYjtj=yLCYmMO@FZ7+bq&MhNxPrxuD#U{1fsdfr8htU%)IONDR7vQTSp(>)!XHc zIDinpT8ZxDAy<&LjC=dVUFZTQq+!4#_?1e@39Lh7$~UWEJ(vbUj^r;zpZ099>VgW? z9`RR%i`Fa@W#jtowSTmH4vQ6v=(1)`6j@<>)la~|KBeclvVIW=x-m%K<=7JLN0f;+ zyh2F~Tn_M!coa$!hXu{+wu*g4H%y*j)6#Sy*qHV7B-0L)@dmGP;+BQ6FE)d$R5=eX zSI_3~Fc>2s#M+CWfPE{ooRM?+zDWGcwq%zG_)nvmsdlE4EKPPPNp`@FC~;~T{oTMH zu4QHGs0=Ulz&*u--o1&De4LJeTEx1`;K(=U*cB0X0DgF@BQGJ6hfF7=IS7^>irM=V z4)D0lpX0RBB%skiop9`r@T+B^8~>GObwD@wqecW=c)$>rg18oP|)(ojht-JY-yQ(vzcSBxC#ndaQ}^M^EW1wjDV) zvB&;|W7bl9>)mEtW(Df6#JY7B??#(o3yldPH;lG*1|?|1Z^|kUaN&kBPMISPevovM zIL<;n+7YdL6_Kv1#_geX!>TI&6I@JFhL#KTnC#TE{D%jZN$?AWNLpNA06@O)*mb*3 z4XoqIl4yEqi_7O zvd(|@s+`i0_b(p9ipz{{BU5AHr@-M4+f`8FF9A`T&`}$Ny4AEH7IYe^4@O|29m@Og zlZ8aI2S6H+e{c1GwSM|3NG~rr`o&f6;r&w9{TYk+bp;XpQb`%n20mvmhzz#WNP?|c zGnaciiNJf*K@JtH;rE}j#HGYhRS0oYE$3Rf^kDOcj60bvA2>Z@+M`Ld!#ZI{$yFA%{zE=pfCt$ur%HKt;H8;R%(fD&Ol?}>|@$|U(i-u&}rpc~a zYk*VB^%f>Y7s2crwh47~eIDZVz2M&iih9dsHx*D>_QNFr15EFDr1(fxR|bW}GDkkp zLq(|J?SBP@xTnN-p^ls5O_FJLmqPIX8seYrg>aDBm)!k`pQq}O2_toy2Lr$ksF6Oe z3R$FIyioF+mZb^MtKW{j;ij5B*U()vwCDqddn{w$6*+!g@Nsf``)aYiad>fQ zMB2J$I=-0{#&VyD@8UeHT8rp_&_zFh!w4!I<)BeGp(y}G!jIbuT_v%EjV{UwcMy6c zlfa1I8B$eNh1x^?ig@ze1!D&czX2T0pmIHpKD_=gZE8NyOV)b*!$hF0%0^*&E~^l} zEgIs{V>D2mJBqO(g6KblM4bik!Tj7&MYwMRXFy9y%zOcwwX;7p-?X zqn8h!v!~~IE>;9}iy0h+$iZxJiex0z!N5-%9-6ExaXB3Zq!aZ$VXrkaZ*`iqu}x;} zY()cKW#cVdPWgYYbPfo0{v2Vt`R)0>+rqRWtWEAmdH6M zcqmbjA;}20Phk4Z&$K1u?v6lO5>HKl#bxW)nO#4xwx~uLK?D|;*#s2jmV3M)B;=@G zcRT}`FY9(TTpp&bO;7kXjpR6Ew^Rv21S!L|Lj3h6h=Z+MjAp-noOO$SK=%Am*pAD8wby z6WWO5CajKM$=*jZ)gEG5)Yi@ob#twA&pZsMlwtj^aTI zzVzA1tK>dcH)yHQynbK&-+ol&r_+7Te&+>|clwY>3Fb0*rbIx_a);4a(i~{Z+Csw_ z2?vvpD`oohsM_n!>2&7eSAVCF@*bb4_A1i{F@%A3 z%F!%io8jIsb3j&zm6MF@yt&v>Bsvasnj`gR6(SeGXKRJE3#tg&D*mq!2fEf&K75xD zqllk}7S1Y6?cH$=xQ(i($na-27>3Ev!{%AvH`y!!!C60|a-ZZm?RuO+a@jF@%zWM; zc!Wc|og#PyTc2^^ZzKQ{PQsq3?#2RtHn!_Xw#_&db>4QTOB$MQ%L1;+cOh^{+et8mSjH=Lh?cdtujD?3Af$^(>Q=j)F-z4=NFF zQRz{cOpcIY6Hf&9SJcXaf39)>sdDH3rGo$Ll@J|OB4#){zv~=g5y$@+3 z`f{UEv+5H!41(hyQ#$yPaTcVZunvFYQ;%$awzj`#gTcTcuO?!Bo#_K}*&K07!6y8D zS_2!??abnjQJO{YbPccGei8Ds4RNbk78KE~e4x;7^4U2HT}i4g;%WvYml$ zkg-rIliP$$rvUqY4!af{@zV$%o?W$OKn4(P?2f8PKjirei^%!%i$I6??5V^s(iu0v z>jUMpv6#0@Gz6i$VovHGOcb@OmO7$2bhy^TRPze?EN(C)8v( zb3kncHH_%yAoJkw9b9zqi8rH{nGomPIx=%ZULKaX7MvlK)qk1y6MR+)LlOEFIA3)G zv^`Uge$Hf+KW`6gY|j=&ICaql6^##vz*+TF0N(0^5;l9tpYd9g93^a=Q7S4g>lV<#mbKtZ8=GWlWT4T7`+a-Ljr z{#Tzpa(;k65HzIkv%}+Vj3}w3j-36)_6C43TE04KR>yZII}exaiQcj!^Q(QHtP$}l z9khb^NXF?cRu>^saHdujs*Zh9g;6uIiYq9G+%sqRldOTMqjl$Fzj8C(w=_l1A^Vbi z#M{5*@%Cjn{WF0!?El7rLgeaS)-K0^{@#!#4g(pF-uCZX@n-CrrR;KfizX*aPz$!{ zWQmNk@0!U8Of55HFdLnu6u%E0%d7|Z5M8EE<3z*xq*<-NvMr=blk$h`jUBe~z}5ki>av2i zy^~&l^^JYF?OsT)F436Bz@%E{8+vWyXO!X{+;*0ox3f>3i#Blu7LAFqZ7kOMWNnxX zK@^=Ujl`=b`X)BLSq-hX8cs@c2Pw()Q;$zu$#l+p`f!cdc<90y)98&g1(e{x;$WO_ zS^IIV1w!l|R%S%DkioK8N^sp~ii-63v$x?Mf}>w9u8+287|P>XAtYth zw9G&Jfqoe#bVLXP=#rusgbm^pzc7Yqpu>iuSm`v55UhOeBSxbo_0h%;G~P}1$}sYk zV%Jx?n@2elH-uGg=QCycFsFt)$gB4Po6nC4*#HTJOTIb zqwQ&cY>-6jMKM?KT=u3VHnV~a7n0o(;w9ntXCsd~D*>vC(%stfx@jAG2BG$5F{cM4 zEr8M!V)7k@v&(ID2e9ixKaTiSSL{XGT!`B;(}IgmM8eSB-eZlY=z1rba$NLS;{4v!?S}F;{u}_gP`P*B6lR#(0ffdrf~k z!M+2o+S7i46YJu@r%F!bz;bBHF;OyBL2)e}=nQNxHG7YY6PT9xN;ThmyHC1M`7i0{ zNM3t~%k!fr(Z`#2hdGV~=o4=F``+P0e=l&Zl8_EX%#|lWBDE`7EPX5LUC#(Cs^Dk| zUc!%^02J3gUGwn6y{^^ez0$JB7=`bA9x`ox84EW=iHuT8&L_$x>Vv8!6p+Tid)R>O2 z6Ntu%9IegR!fEarN&^<=54ej3lFi3}o12yTD|!F6bKet0`7@na82fBGnsRG=KB@tZ zDjE2bK6RQ?P8}OYm1Aen^`^mut2+2=^_{N{hX36r=R#kRsor7r4e*K2{vO*~`14Mh zv-b{Cw7)E*9U*Q26e(Z*UYMw(E*f=o_`A6UXCg_=y-0|xB%_Wz#ThRU)@Mf;^-O3z zq>};ap(<*wKp+hTAaNnOy@{0>IVK5Rt}W^=!DoDpHu*7X259Io=_6Tmb(yMdE3k@X z-l$dBPvFXfkUPGTNx^5Z>nh=8$6;Fy!GJ={d9qRZi75uE&fWA6HRvwc?jIe*L}ltmdLLdGJ_ zmRMjSb|q1FlYq8j6li|JhL7lr!bVUKIeVNE@KJ{mG1gH$SU=%B;$@fWsbL&M;LhC%$uc&{(AS0yNVU)x?smaY2P>L4Ph;+hg&wN zdbE`qTa4d&jdnh_9$m9%w37y%4w_zGR+J9_bm6s0=*qy_#pNA;^$8b9x9=6{74~0+ zeUeGbq=2SdT_T^R#C)YoaIJtl@H6*fqN>*its?P26P0F316+C00o>^FFg!7UUpoMU zv(yk;cpa4SFl1`C>l1D4`f zppMk3QWq4OcDMIQgxYM^{VPbx`+}8NfMlB>H3&A1sTiB)s?*A`i$S_o9<2KOClVzn zjr3UKWmv_ELiV)do2uML|LH1H+WK-U3Xf~^rk=!Oowz5sT`tES5#eDcPC&)fGrjBD zJtmMZj>cQX2_FRH1`3?Jn_9?sP3ZVhx|32=TQZsI6mSZVX-GIVmrCR$ff4PU>}e}- z!uWTW=wqQ;yZV^#!_q#}7}=oR=d=dB_?i%no8HIk@6G(GZ4VYiV;qQwKh>IIS$l%r zPZ1m~Gsu>!#Q-jZSZ~k+ipYCv58Z%l&qVZipP}E|w|Mq6l;joTv>?wxMu6bXl`0J2 z?LO$ulAM|(@@+rgp8Cn=Czi`ofzf|aS!)Eac}-}}UG9>Dp4w_}_`Teo@AW>Bk}nYj zBHd;cRhjNxi22Tyy{CQ9u8q*?R|Qnsc@=?M@N=M#6ZTXXb_#z!aC9oR1WZlHsPr5B zmV2aeqBs2apE}+Jow))+VwVb`h5Q}#p`hW+@-t%v-YG_5b_P%$O>dyy?rQrW17{6% zL7&6%N(*S5tg{D}c-D>{_ z{W_^Zb6x*|PnNCunm7on@#^&B3VK#jh+tZ{X5ym$U|intkuhLBP)H!ANd2CCH24t` zMIqIU@J0P_gy+1nS@s=2ao2C-{oXXeq^%%3a)0UG*)`0XSFe0JS;AGY1NT5*-K?fM zs3t~NJ9MN(DH{sG3WexoL5s)#Y(4V^_?iv63L&=v zh66>*Y{q2yp9EfzYUXWLDx)%Gf45k7}dH}-CJJCt)76y+oA z$dz-Ii7qo2)GErA)TijH?<{wup3R;pF7PknyD{wL9LZyzEc$c7y1mjj^AJyK7Po|VSetGMuutf!z&OE= z69e0Jy+k{ooPyak@2YKC+Ly*2Xy^d>Kj!%$J$1;7wdek#&z#I;QEE?#l^Fm>)5DRz zgU*Pk3N~aw3t5*3E}xHyzlvfTkm0_JKTENOJ5JCu^*eO|XtXS(Fy~XcTc+O;?MB5K zxG#TH9~}TqUXX(4=dycZy9M(h#@KF*$w2i~rMV5s-2y%VdMV)U<5AChWs=Uxc$Qn! z0Q~hK=c9pTo&lF$$QcJwh1(s`{lye@7%s|@huqK-d3-6#l~vs z_BrVeG4jBn?bzoPSC+GH*I(k0BP@sco^n9v zc!?J)S-}Bjl0oQ95{H&0Frkkjrx+==)wvsw(Z1v~dJ{6z-L@j}A8~P0nn*c&#*n z>Nf*-N#p;m61+TDie)N+j|1DO+booc`5M{asXdB*9d*S4dwv&=3sIl8VX$fl zW!kxtWZ5YeTa^e+P#JVN8S&CBoKx2BTC z1(g53OEhyJf&9iA3R%`Gv+49FI-FAI{F#)CLE+E@H%O3qHe@0A;2$=;eE#Bow?Wm6 zofV9Rt>2xolBZ|j_7|Wuy0GCzz0;Q6t}V!?1ta`J7vt13uJ|xdJof%Vzd1~X4w+=< zq(N~#v-28tygE94e#pk&a>D3{y0$n!EGil!T;SDzgLXg-6(u`<14(ufSX1k6zmwpf z{C;ikOA{?eddJI{=!YP$04Txj_IQU99f+>c{KHZhnNI~jGH|0k4@*v^(_ZOBUkB#> z!8@6E2>misO0LOr5*X5#Inh*9Gp?(_%E$rlC&w86cr&G@T+s@A(*Bg<%UYdWduPuC z+kRf02K}trxDrMFDB$+0Wk;o$@?cS}GnxiqGx5<1)cYyphbFk&ild6nTwXl! zh#o3s+1G)I0MW$9`PmXLR(mw=u}^&Y_Bq-0#TCu}XqXvic%=6&H6A`B3-aJkXrVxKv{h6aWXMwO%# z+Ej3$F{4kLQEB`xW&=hu-Om2z)08U^o6S9>@CE57R9 z#r_=HZK;6)|3ZP8%qb(iMrnRM-br*nOzmIuC@xaOQ5&xTk}ZJqCf*!pr%#&mt;%AL zi}S1TE+0aq)8JSXan}aMjvD!jC86G_4_nhiHIO${El+pKLbuD#mg6{kjg{%o@20X5EkG+Vuwn-6u!mhz8|v?08#Hz@->&N`MqUlyc~jVItdgS2ms&; z8y60YWMr7^4Q*~zKsk}wYbl~x;nmFl)WC6e@eJ=C>j2DQ!_eCqY#+z|RST{G%wU4C zSCt-uTJH*ysC!kgI*p>7Vsl+1V`4 z$jJj;q8@H)=dJ+58eOjo+D0`oXWQeoeTJIwtITL%#6tb|`BXjW+wyL2!xz#2_8kOh z-+6CyKmhGKYS6xu_p9Kh!5?l)eTe&<hLuvUq<%xWJg4idfrlxm; zu^5JkQEw3lw;kDRmCntZDch;!L!D?o*f#6#Q!9Y`y}~a75|Yd}(EhC(-)edCyk;bs zm)H5BCaa~x$^wlCeiiQE9S$r{9FQ*doe^5_b(HZ~ALOPusp5T4i%kTqI> z=NRwcv_T39 z2VrX9pNO>w#;V#YmD&npBKj3|rxn;IWXByyuj_Ig;yQm<_#b1nKe=!);~DJ>dYc25 zB1yD)6&%8zKcUJj>z_M%(}ZOOCyTJq9t6)5*-8`gJq9W~A+r6Xl@%sQE@CCp!l*L5 z=+Ya;Om|c9oZy2g zH5crYK}VU0h_tx2+1@C7Mp3Y&L!VEFc<>_+kR|GpSDl`n7Sio&(rDeli29tXGetp2 z8|lP*6H{Wo@^apY5~ORdIXB&`_S=vU^MneItUoJ_8l+}TL48DB>Mx_^*86<>o8u+*a z^GHO#>vLc-NL8nAb0QG2UQKyq-6CfL*jSw9OZMc0efZgQ0Ip6_{ZU0O{?0#P(oRx} zhnv)n!}WXZn zudL!x!|Cr1Bi|0u;ZU#e87shUK6N6ObICf@?BMGx>ZI^d2ZmPC?l&492rJm*3P|XO zN#R4rWwLAl0~3==IE~fTt*MmSk==;XX>hM#5Q7*q>>rNqf{{zF-%W(mlka*fIoLM2 zUIdBp1&v??OZ=QcSF|%^w!sqUk%Xx+5>v;*p$K!6b)oT3-xyEKfXi`6cOrCMp_BeZ z0>vYrNPx!rDi}QDo+(3q^S22{>e@cOF9%+cXfpvq zP?MWV+z|*cazI)hDD`Ffe}N}Le17cdzQ_UEjqFR=HR$c@f7rrt&1?CFa$8_Yb-rel zTA^*T2N=ZMDIck|QFk8du<`yH9(09@8R!5p1BX$fPa(r1fA{n*Q}eu!5kLS55vv5! z;MVYmdX^lp!Fj?!XAKzkQr-6e2jrB(WsQ&8(8RI4+SVH9JPUbV;Yai~UbcbLoq(~v zAEE64w`>t%Kg*Lt-CFi5cda>X*$JD^oWv_3DezSOvWM;nQqeSeGB?YkP8D%_y&E7;M?n7_c zvCu*r4pgNlLCy;_R3C?5#bde9Ou>a_3e&e49tI4#_LjGp0kPtMfI!lZr2Vk3?OKU1 z^@=;mz-32HE}y)7?O2n;LQ0#iH0irmG5+&I#(m{9JS|5q9}{UnO8q8$Ck!jd)v*u4JPx zkgZ1mlbvSzWww7()H>byT=h_AqTGc>}j@Okbc&rQqD@S1f!blmXP5zzs;EeG8{l1-sS|1 zu3{ijabNlg$gYa1c=>zT7=Tbz9pF%EA|!H~VC~OUdR6lOB-x_T{D5fzsk}ycex=Tc z-{(DLH;k})%?j6&ji59C*!v9QJ;Pdn=y5=v2^gj(a&*Pogo<1%>>J69Y@>ALbe|Ks zjI!>7I0L|Pe-^fjs)JVXh4?L$8Db2*0e8MwMbnzzyrS@AIjaI06N#-rdAarmDk3mx zjEES7mYIX<*4&%tv!?j}=jpJ*Ewl@0B=%VF6Hy|G8bans-MlOpj(J5R+UG+9k@t@w!X zND*)Ff4u;VD++@uz`&V%3;JrtnapRsfGfot5@1|Clq)W{f?m0$S!3A9?<>17QIHol zC)aZ*;~9@wJlK291+nK|R|&&i^9S`-N41(2(0})sXO2iicI@uWXEvxP(rPbo=A!L` z9;A;7fDyW%7O>$FtuIl>(Lmr~zmXqy8I4`(2L8f-LeE*Ou!bMN?XGPttA-vaAHk=e zcg;G=)!b8K#5Gqu<2fEfg2`j$bK_O z=@RfrD5jP!1oh?gf-Ms$0b2CuP+)rb*ZrvsIq*;BGUh%n5&%D=eO}44HNLvD;o84M~5<13B5f_haNqkGY_1upB1j~7png;vSXjotY^n-cqsw)&Q*XkQ^ z{`aZFsTJtl1Pw$8Et`#x&SHLw`!?_{WGJweo5@;5HTNMYR?3O8wM9+gPHVm*Nr<;| zQ`jeLn0oc63ViNL7t+oi{KJ&bUcf{d8{D|%L9eRcSf-CED*y7{LjFUe)2TGxi3tOW z$5D~TyV28g^BV%PQ9A7yVL=a907HoZB+ZErB&FCV;*(-kUb5#FrvjdxS_NQu0sQfS z@yna;wje9Z(Hl@m)?{Y(u?;od@YZ9?gw<1>2Aa}Eg?UX4(*|r2)xnu4V98@97D^-3 z;TsUBxXAh+h+zvJnsq3ev;5Gka|J*thuBbk9YhRRs0~5?Ia)rjGOk0`jo)Nf6!tVo zI7)hnTb>M1L!ws1(^P^VVO#>At8JBY0mk8Jp!t61ixRzdPG<-a^Ygop^f4lC zih1q~=uxix&o6PKcXpN-JaLYp7nLPI)ARU(1rHg+VqCi})0tQ)7poF|{LKDR^TOPy zY!?C?&{3|8nIRjFn0T3EAzxA{!B86W2Fc*u3o{9&t2)s2uN`G*erG7$b4h1^yCl1k@1LPbQf#bAVYrG<;jt zSZ1Rp9N4u#p2&+oSP%KtMdv7;tETr*SY;yfhoV?I<=Af0|J;FDWYPaknd(aK)?D(r zd)NWqd?nKSJk>}5vbvchDnZ>hIz`Xgq#^}?4lV{{<$YjnYp8^n0}xVHkH@m5-C&p& zo`IiFsFQReZ-%xfh4=xR7BF#E>p@D3crU=~AtHKK@cii+CbHZP zD*`AE)2CS?T_++~!22F1dd+VK9i)&?!&H4{@bdHj`fbLzSysoC7kGeD<7s@vb}WeY zgCAGS>AvM)e`l~~+%&4iXbMh}BP~bxaf&iL6oYe=D(sQX<5l5aB5hnox@fU|(oX{c z6szpXokc$LEb^ya`o+q@?KJsY)iB5)g$uwXBf3cvlodkc2NxImnom%Y!WL-V?v-4p z4Nc7omZB2_iqFEpVzT1Bq_AQwLJ83AV~W2Akh40;G?uj{oicz)NWds_jFAzS=uJNd zw|$)N@X=6d>q`+W5gzSsZH+Nfe@4FDQs}stvA3f|S=5~hIMU2(j?dhe8x5K}^#zdP zCk5{ngMr8HX;w9x-e)`mODxE$0Vef?Fxf(6i~oM_j*GjcpJ48Kd#B%qY>WimIzInSJ*7T}!8JZD>>1w@wr5KI710QUwEjVtc3_m7&^ zBjH9hmpFzjr#J-_?Wc*Kbw!aEv*w#DkV}UZmBzf5)Os>6M(*yyNXq5$^4c zT87r%A*m`T_c6bIz98%X909@S&bRtO#pAm+1gxoqu4oD7i`fLV!=J`JH0fhQ_AhY( z<`S_FFE)Afa|X02MF$<4RW{y5zXs z@c;vd@0ZH>BxmKA)C{LC`JO5P481>CVmY@UgZB`o+LL zsw5u#2XPe7u20fRQKSQ76B|yNjZMN{Gq+2fr}D(p2rBjx1KVcMuM1w0*P5Qd4ic0> zAzyvP3ofz*I$a5ujQF3#bNNS9Ih&BGn|0x7faX*8%mVQ8lI`j6K?hfq!zw8!n(`F! zIY7z@i%x3Kt0Vp|r~WWZiu`_6?ceqJD&{8UP3+dg9Yu@C3zLZv*&<~YQeoANA(sAJ z4o1R6`$nR*ei%kg+x8QQsdQi9A4X4ni8b$niJb7&uiG6Et5++sTbW;^EWCi#B=PSz z0|U;=ra3skiH8)c2k!)dy;)7~smiiPUtd_CY3F726>t#eda6WP#CVTP>oYXp(k)GFNhGBy0!FTP6rU|n2OVYW0BVJt0Dq|YmUkguvDx{^KI_h4WK{f zhNUr${V`H^+m}C=931v57{gri-XwF(6kbowRVn_$*kzz+0_panCGS;+4-N~X*Ji3X z8W;P>Ve;0@H)5m+jHRPP>x)eRzt@HebxqG4_cEi4h~*G7JobH3v9>*t}vy;bt z&`BD!*>q?B^4a6sCI5*Tw-?Dzqdt*d3N|| zwaaAGdr5yU$}foe{>4^q*N;SR$*_Zr?TQj1!NJ_4w!S1y_HC^u-lI*R?$X{=YRY z<#C>(>6_Hctw4&hbf%ksc*lm?U8|-%Y^;h!{D|kA5&D|quPMAOpV<)4L+gYzKXP^0Udb2SE@6I>%QR*4-hwd=R{i~=aO~g zJtW#GnIWU*=wufFR_J#Qrxp~GgU*>R%4;cTqgxd?1{*OI=Jg*xlyK;v{;H-fvb?NX z*S>`R4{m&c4ZTazEgk41zu|{sf^`gWH}P zAdnpgDDjbR*B5OViNPaZmv5TkOP3JC|XrT`gAeu6L{srW!Q}5w**lN6VK zI@&q3O@}^|R*bjki_^t@Roxb=f>=@LwqY!i-ku>pP>lRW9(6JD z{)2hQ*jTFnFNu5;3+7vnzros-x`L}{4|9Ei6|Qq4_`@FT%K_`~79UXL2~R8)4EruYlF zB%Vh~f21|gDk!hly0?7z;Q%2e#0!;Iya8Q%VfklH)F}}jSYl0`KL)x+T3NozHAp;h zG%K^9I_eOuSb^^aCcHcA{TlyK>I}a_Q>eU%q(yZ5-c<-LH>Y;Uh~DxeThjVhbpk`v zzmGe$z^aM`7Z@ochIkt(V^~Rtn1=p_0{m}&cWQ%^GTzIdWMfWAO#4VB6C@<$hY7Y8 z2%^e?6H@3xO>Ss2dD(>N1iK)6B>JKzR*V%I{2R4L|EZ{+FF5+oPLL$dy+Lv|?9b=g zU$#bEQu2KZFyA6b8tD&2ZArX&kOyDiHHftjBi+8;O-#~g3S)JQ9`?&Hf)&0UBfb5{ za}=S{i~IoN{%7!4SsqPr+vE?yacX+S+1-bR?mnHg$G66a9%hD4M@AXd{vpIMRlk$T z6B;D#xRe{|0O#wly1J1-sb*P_|25r~=KNns!)(}DPnT?Rs81B(4lTGZ+$rE{_pL5I zZj>nPH6_a}Nck+$2DPJ%nsK=P@JL=@njhb0J;% z9*_Zy%BkN{I?{=ddf4kS)AciP{K#9fT^Sor z36}pI{ah6uA{Z~lbWoYuX1xD3z}>b8iwJSAxwY>mMijklHi=nnuC(wHvlln8#sM-G z{8-2Io+*dpD5<@$xqNvg>CX%x zk%^PhnkikHszg>0zJSM?6OI0PMUYu}Nj?0J9kgnWq=FRmy$)If>aK!kBr%*!fRKBv zbtb1IbHNV#tQFBDswSe(;$$*;g*B4XmDWKF9&IwO6pxvg{qWc-`M&2zGb>RD_b(4k z{Yg-fXLEb5-Kl%`m|<44^*LFD?CMq*(Cb|%$I&!eeQV+S?EDA@0j0;yL_QUwWEsrl->1{r36_R~ ze1ifeg7bWXGu$W)<2$~i94P`WJ}qOVc88vwE*~-tM=UKp9m_?Al)DrC zGMILkNVh^VEWCv8L|63(_xZ-=r-nR82DS7j2TNS9HX|8%PYIR}7qT6PM+LRZ(2wyx z=_qKtIu|~elyzf2&c@4r{y{4V{Fi*Hidl&&iAFQ+v;X(<2eOXxz{%X}|U<;iYMISVL&@4L(p5)7t*kI?KWtv-?5i@@5tg@3$x{urBK8&$i-~^A;q=) zR!fAeDt2;YW_(<8+s3*io&PgJUpqhsk0+b&bfV092ai215b@89+R@~AqI33MzcXck zuH>>jZZyhOib>Iamh{ws@@J7O%ly2@wY_m?wo`=ti$P##j)JE%V)c{CMQUciD^{wh z@iJ@i$FKVgy1NFTi>Wl-alz2v?L~WM?akWXDJL5w8_YC2-7)COL_3&S_~Wc}w#z;; z(y*zvjkRojb6d00X9*8yQ@xA-S{s*&;49R?VoUFu!B&K6++OwUWo4i+eW}$t%V8Ls zT{yDk%Cdbhf8KcHgWY$kJb2j|IW2IBm z434px50Aa0%~TyIi-_coVXUb0fW&=M-yEj8t?(9C*R_9u=~?x~};_EL=tJrMCM zxiRlQrm6LV<^28n&!d=5-d-edeQa9Ze!7L_`BKZ!UHSWWj1$^DbL-#apN65+$S?_c zs)s$C%M>fQXYk@c?VR#m_GBEQfb&A+O<5W6Sy*?e(eCivU{fwn6*gT=_8`WEKDHkW=&|#jixyFZSi1ty&G1>1KZ?G(I@`ZrqM+7P%V%9(wENT;I6 z{XcCge>6BsV@v(CtF1Rf2a~=U{WVjfBb(JGi^BV&PRB8u60ShYd+mHw7XHb;{nE|r zOB@}O7fp;m327elR}1@|ia`_wHu{P?3*8}OH)Y$6c^(yIo`a%;uO(#tTG`vY{qx%< zsZ08UEXNGxKkW`uEv>KLhUvU($X%-`;>rCrkjpbbUpk<-D)nO|Pi@%XkdLG&PF_To zr0ODyJ`8yxw!oG>d2q1I^@=aXL@Pxt)ctS4RE&#OR;1nl8Nyf@E(UX6ubEO#^(3A9 z)iBv160yptdKcB`Lg5>GC3b6Um8FhVtG8OR@CS@hvqEc1oZLVW1{Y(AL31s|nR3OP74FY=N3U z9Gk_ns{MM!Dl2K6O-`fNX5!M{{R8@j*=nbofO`?%pV>@LZLcqt4m_un+gcvSO}Wo_ zcgEvpdTrwd+DB(17H6K*O@^w^#;0dW?M0i0)x#>M7JLH7gGznYj09( zQnwE8s@UXz&E(>01b*}y#!d?qxf%pQQ~+Nrs@iaUd!wGXE`(Vbqh{}Wc#8Sp$-t&W zqE!iyfo=P&|B{O;l*#q2c*6$OEJA1-O42sv~+b<=8#H<6eMOr zMIP*9ar@oS1j8u++V@{YQt(o^VD-))XR$`2>jJjhKnOugBBAkPY<+#BFVasKdP7Pk zUNDMskG@~3WJWj&>kfr>Y(Lj{V9T>51E2CLsZi>^MA-U{$DP!!A>YJU4fx8FY_oP`}4 zW|6KxDt-`vjLlDo=C{26qfFoXLmo3r=sYh@C!qF^`JpE5(ISPpBIU9z+~ZVO%}t;Y zv4q@fxDIu?7TbRQZ<%^_imj4^U)VWHOS%RY2l;W7!WBrWhs_~~>T}udf8xb)^so!{ zTdqtiM<&BHX`j8;GJLoBZl|+M95u*ZkHE3RB(owYHKWe7bT~*d)(`%xDHnVuYx9p{ zn1t{c!~&DKjt!e=Q~!8Y2qg8rRY=u9uY7)@j~bEQ5J{khibd4 z)@i}KaK#%xA_6jfCuXn5CjRo@E!-nc|6hj9HtEMww~< zq6}jH<&z2KMRj%&UpY%*Ks2m1-Cp7Fc7$c?;ed zOT3nCdJ#uIx)a^;cdXCFBEJn`gJkzN8`xhy1WsLQZ*IjIJQ!bBL>~G%Tvg4T4%~f` zYB?}d6x}sSjjcIxEk#i+EO{yPzSLzo@>gw|X@4>QdGW#w*hyNp-#lG+dx311Rf7c+ zM}60Jv^b*`1wJ5I9Zw$gjWe|RuC}41{=4;|UA~VS_PBoeLb07*jb0spEsc5i;QX|@ zsk&ReM%JNpeN-dFd*`iBW|Jru+uo#yeS*>?^W!=HNu-9ZmAe==yZqtMDcU>0NIuci zFwWLs_KzGWrscQ17ERa2P%EFJ-jm&SGJ4&-Oo_)e{t!XoFWl0WMQb_m1u@9uHLi4w z>JK7w#V}STa|44ohLa5Rp$-@)2q3|pgaA$SWHx6iLqUR^>VfRf3oj-=(xaWtIs{j& zHKdBX_+MX=iit$Z+1g~(2>(H4U4&<=Dwom$iJIN+Z|@J4&D-dW_C=dD-*)v1#Ql

Za%OR0uxa16$yAHTNME|DxYdXqxNs!qRU$iy0m$ho0N(~_i5d<6-{yetI$ls^-4 z0cYSe#d3*{4XWug`e`z{{JhcfdZJLaxRB+UPi5h3*-cBD5M{ro`t;a6BZ8q!>D3ubFP;&SDAFs}^ABC0NF)&gR2REv*d6(IGNP0ck#W=+Oq)fl?yN9Bjl4u?4WFpiH7)x( zHjU&NT>osFz{Qg_qixO`qfC>KD;K$e1%CIEO4-ak^K;jP0vyx1?vsLX@{Uvh(rKga z$Zc)C#ittWC@-xFW0mObo5O`@`Xj!9V&~pi_146#tFblpvN>EuNhg*=a0X2}AmiuM zu=k<;OT@e940wlplW&KlVGz9Pj=Aj^jFr9zGg~HhoKH?m&xNFQm{|zl<6gqq;9q>h!P; zSd#iJ5?De@SV2d;-vbJ8sr}`rq7k6YL^$HoHBYx#vLGaMXJmGjYEbi8Q}(*DXES82 z?9NDxmw3IxyQGMB_e4EkM1^xF87wV~wP+L4|}^dMJIAhrg(vW1BlqNSoJ0{ts7g84zXv zd=E<~AfSYRbc3{Xceh1LNl7(v5<|!V*hJFCnnN63?~wx1Rs+9r5Z@ zGiS~@GZ#}|P9$6@Y0PwVd=+1-Dl;c~OZ=F|`LFBNH0vB|&JAB9Q6E?X*%CItpA`3KIn1Q?*uRq)+fZw;ibV!=oZ4v9sAAeFKb+ln4wMh>hAsI3TRm z=u71&bY(2f!`r=z@+Ko4x?N*NJUpt$$TAMTeR|6=Lc%WXN)LT2Ie<~8Tt0Gfsa50| zwQZ*P5V-kV&>~2lc&~jh|NeBS)|wi8D_x>fL8fdZ|qISAP8Co;(y{iusKKRzFzrx0JE(Z_O8q@z+KBY6zNJN{W81uUA8zEa7 z$7aoa1Y}{OS=;9pzowGkdYl>};#}kBYrEAI<=UM}^qHV4ZaozrYMu(tOS9ieBqi>2 z5B^fO)7m{385(?cVRqI`{3#o*m1(g?V}VZpu*)4C&AkF3^srX;pglTw=LaL z%OnzfIsHiDOUaYU2&cHeA&uSdq}Kk3Gw(hUpW142|ES)#B&PWJ;@Po5sorG+`}E7H zO)FKX!Sbll-Pe={&zz4Beh*$2U1CX0w_s&+=`DfM>lacUyxewO`ig5UMzm>g-vSKu z8k{%NgcpaeR|&7crd^*(TkkeTHs`712b)~yH!q~CxVxU z^u6%6;?6i3nUeB!dZfW*9=tYtkcj>XM_B$yS%Fqep_;zJBaM^Sz=Y4f$3TAuq)K@) zmE>W^y|Ew}k^TEKxvqlK1hT(1(zgm{jN%9!FqHsMbNh* zC5s6{!;S-}+Vvk5ql?!2hAU(ytm@~gkEm`;N$w>G3LD!iW&p*_=*5GAq(**~X;{%N1?-j0C5FcurUb)iZ8P2=QPDOcJZGjv9IK+AH zA{sp3wu1AO8unYsd9~%u#!4TaJ&S4@+lD2Eczg|W#BjfUzaTTNyUqNYDVfym`oZ9g zs*p)Mm~lPfZBYMBza=hvQ*VOrjDa zrKN!12P0Z}3;psw&D|KPv_&`Qb#>om{OQyZ8|)g$jDDVVuKs^sxF-JfS!w8&pJ%>lv7q$ zABU6i+q}YdYcTCst#j0C)Z+j>SbqdrY�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 MlK#c)3%CCMFNR>_Y5)KL literal 0 HcmV?d00001 diff --git a/HQMTool/HQMTool.jl b/HQMTool/HQMTool.jl new file mode 100644 index 00000000..7d890306 --- /dev/null +++ b/HQMTool/HQMTool.jl @@ -0,0 +1,143 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using Base: CyclePadding, Int64, Float64, current_logger, parseint_preamble, String, Bool +using Printf +using HOHQMesh +#= + A program for reading, writing and plotting a model for HOHQMesh +=# +include("Source/Viz/VizMesh.jl") +include("Source/Misc/NotificationCenter.jl") +include("Source/Misc/DictionaryOperations.jl") +include("Source/Curves/Spline.jl") +include("Source/ControlFile/ControlFileOperations.jl") +include("Source/Curves/CurveOperations.jl") +include("Source/Project/Project.jl") +include("Source/Project/CurvesAPI.jl") +include("Source/Viz/VizProject.jl") +include("Source/Project/Undo.jl") +include("Source/Mesh/Meshing.jl") +include("Source/Project/Generics.jl") + +# +#---------------- FOR TESTING PURPOSES -------------------------------------- +# + +function runDemo() +#= + Reads in an existing control file, plots the boundary curves and generates + a mesh. +=# + p = openProject("AllFeatures.control", "Demo") + plotProject!(p,MODEL+REFINEMENTS+GRID) + println("Hit any key to continue and generate the mesh") + readline() + generateMesh(p) + return p +end + +function iceCreamConeVerbose(folder::String) +# +# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# written to `folder`. +# + p = newProject("IceCreamCone",folder) +# +# Outer boundary +# + circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + addCurveToOuterBoundary!(p,circ) +# +# Inner boundary +# + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p,cone1,"IceCreamCone") + addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") + addCurveToInnerBoundary!(p,cone2,"IceCreamCone") +# +# Set some control RunParameters to overwrite the defaults +# + setPolynomialOrder!(p,4) + setPlotFileFormat!(p,"sem") +# +# To mesh, a background grid is needed +# + addBackgroundGrid!(p, [0.5,0.5,0.0]) +# +# Show the model and grid +# + plotProject!(p, MODEL+GRID) +# +# Generate the mesh and plot +# + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + +return p +end + +function iceCreamCone(folder::String) + # + # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, + # written to `path`. + # + p = newProject("IceCreamCone",folder) + # + # Outer boundary + # + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) + # + # Inner boundary + # + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") + # + # To mesh, a background grid is needed + # + addBackgroundGrid!(p, [0.5,0.5,0.0]) + # + # Show the model and grid + # + plotProject!(p, MODEL+GRID) + # + # Generate the mesh and plot + # + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + return p +end diff --git a/HQMTool/Source/ControlFile/ControlFileOperations.jl b/HQMTool/Source/ControlFile/ControlFileOperations.jl new file mode 100644 index 00000000..2e38c2be --- /dev/null +++ b/HQMTool/Source/ControlFile/ControlFileOperations.jl @@ -0,0 +1,316 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +#= + ImportControlFile(fileName::String) + +The control file reader parses the control file and returns a Control file dictionary. + +@author: davidkopriva + +A Control file dictionary contains the keys + TYPE + CONTROL_INPUT + MODEL + +TYPE is a string naming the type (class) of object stored + +The CONTROL_INPUT contains the blocks + TYPE + RUN_PARAMETERS + MESH_PARAMETERS + SPRING_SMOOTHER + REFINEMENT_REGIONS + REFINEMENT_REGIONS contains a ["LIST"] of + REFINEMENT_CENTER + REFINEMENT_LINE + SCALE_TRANSFORMATION + ROTATION_TRANSFORMATION + SIMPLE_EXTRUSION + SIMPLE_ROTATION + SWEEP_ALONG_CURVE + +The MODEL dictionary contains the keys + TYPE + OUTER_BOUNDARY + OUTER_BOUNDARY contains a ["LIST"] of + PARAMETRIC_EQUATION_CURVE + SPLINE_CURVE + END_POINTS_LINE + CIRCULAR_ARC + INNER_BOUNDARIES + The INNER_BOUNDARIES block contains a ["LIST"] of + CHAIN + SWEEP_CURVE + SWEEP_SCALE_FACTOR + TOPOGRAPHY + +A CHAIN block contains a ["LIST"] of + PARAMETRIC_EQUATION_CURVE + SPLINE_CURVE + END_POINTS_LINE + CIRCULAR_ARC + +A PARAMETRIC_EQUATION_CURVE dictionary contains the keys + TYPE + name + xEqn + yEqn + zEqn + +=# + +# Four objects store their members as lists rather than +# as dictionaries + +blocksThatStoreLists = Set(["OUTER_BOUNDARY", + "REFINEMENT_REGIONS" , + "INNER_BOUNDARIES", + "CHAIN"]) + +blockNameStack = [] +blockRegex = r"(?<=\{).+?(?=\})" +# +#--------------- MAIN ENTRY ----------------------------------------------- +# +function ImportControlFile(fileName::String) + controlDict = Dict{String,Any}() + open(fileName,"r") do controlFile + performImport(controlDict, controlFile) + end + return controlDict +end + +function WriteControlFile(controlDict::Dict{String,Any}, fileName::String) + open(fileName,"w") do controlFile + indent = "" + WriteDictionary(controlDict, controlFile, indent) + println(controlFile,"\\end{FILE}") + end +end +# +#------------- END MAIN ENTRY ------------------------------------------ +# +function performImport(collection, f::IOStream) + + for line in eachline(f) +# +# ---------------- +# Start of a block +# ---------------- +# + if occursin("begin{",line) + blockNameMatch = match(blockRegex,line) + if blockNameMatch === nothing + error("Block name not found in string: " * line) + else # Start new collection + blockName = blockNameMatch.match + push!(blockNameStack, blockName) +# +# A SPLINE_DATA block is special and is read in separately +# into an array and saved in the spline curve dictionary +# + if blockName == "SPLINE_DATA" + ImportSplineData( collection, f) + continue + end + + newBlock = Dict{String,Any}() + newBlock["TYPE"] = blockName + addToCollection(collection, blockName, newBlock) +# +# Some blocks store items in a list +# + if in(blockName, blocksThatStoreLists) + newBlock["LIST"] = Dict{String,Any}[] +# +# If the block defines a chain, get its name +# + if blockName == "CHAIN" + nextLine = readline(f) + kvp = keyAndValueOnLine(nextLine) + if kvp === nothing + error("Key-value pair not found in string: " * nextLine) + end + addToCollection(newBlock,kvp[1],kvp[2]) + end + performImport(newBlock["LIST"],f) + else + performImport(newBlock,f) + end + end +# +# -------------- +# End of a block +# -------------- +# + elseif occursin("end{",line) + blockNameMatch = match(blockRegex,line) + blockName = blockNameMatch.match + if blockName == "FILE" + return + end + if length(blockNameStack) == 0 + error("Extra end statement found: " * line) + end + if blockNameMatch === nothing + error("Block name not found in string: " * line) + else + stackValue::String = blockNameStack[end] + if cmp(blockName,stackValue) == 0 + pop!(blockNameStack) + else + error("Block name end $blockName does not match current block $stackValue") + end + if blockName == "SPLINE_DATA" + continue + else + return + end + end +# +# ---------------------- +# Comment or blank lines +# ---------------------- +# + elseif isempty(line) + continue + elseif line[1] == '%' + continue +# +# ------------------------- +# Block body key-value pair +# ------------------------- +# + else + kvp = keyAndValueOnLine(line) + if kvp === nothing + error("Key-value pair not found in string: " * line) + end + addToCollection(collection,kvp[1],kvp[2]) + end + end +end +# +#-------------------------------------------------------------------------------------- +# +function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::String) + + deepIndent = " " * indent + for (key, value) in controlDict + if isa(value, AbstractDict) + println(f,indent,"\\begin{$key}") + if in(key,blocksThatStoreLists) + list = value["LIST"] + StepThroughList(list,f, deepIndent) + else + WriteDictionary(value,f, deepIndent) + end + println(f,indent,"\\end{$key}") + elseif isa(value, AbstractString) + if key != "TYPE" + println(f,indent,"$key = $value") + end + elseif isa(value, AbstractArray) + if key == "LIST" + StepThroughList(value,f, deepIndent) + elseif key == "SPLINE_DATA" + println(f,indent,"\\begin{$key}") + arraySize = size(value) + for j = 1:arraySize[1] + println(f,deepIndent, " ", value[j,1], " ", value[j,2], " ", value[j,3], " ", value[j,4]) + end + println(f,indent,"\\end{$key}") + end + end + end +end +# +#-------------------------------------------------------------------------------------- +# +function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) + deepIndent = " " * indent + for dict in lst + dtype = dict["TYPE"] + println(f,indent, "\\begin{$dtype}") + WriteDictionary(dict,f, deepIndent) + println(f,indent, "\\end{$dtype}") + end +end +# +#-------------------------------------------------------------------------------------- +# +function keyAndValueOnLine(s) + indxOfEqual = findfirst("=",s) + if indxOfEqual === nothing + return nothing + end + key = strip(s[1:indxOfEqual.start-1],[' ','\t']) + value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) + return (key,value) +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::AbstractString) + dict[k] = v +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(c::Array, k::AbstractString, v::Any) + push!(c,v) +end +# +#-------------------------------------------------------------------------------------- +# +function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::Dict{String,Any}) + dict[k] = v +end +# +#-------------------------------------------------------------------------------------- +# +function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) + + if !haskey(splineDict, "nKnots") + @warn "Spline block must define nKnots before SPLINE_DATA. Skipping..." + line = "" + while !occursin("end{SPLINE_DATA",line) #BUG This will read one too many lines + line = readline(f) + end + end + + knotString = splineDict["nKnots"] + nKnots = parse(Int64,knotString) + splineDataArray = zeros(Float64,nKnots,4) + for i = 1:nKnots + currentLine = split(readline(f)) + for j = 1:4 + splineDataArray[i,j] = parse(Float64,currentLine[j]) + end + end + splineDict["SPLINE_DATA"] = splineDataArray +end diff --git a/HQMTool/Source/Curves/CurveOperations.jl b/HQMTool/Source/Curves/CurveOperations.jl new file mode 100644 index 00000000..a7de2eba --- /dev/null +++ b/HQMTool/Source/Curves/CurveOperations.jl @@ -0,0 +1,243 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using Base: String, Int64, Float64 + +argRegex = r"(?<=\().+?(?=\))" + +function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Array{Float64}, points::Array{Float64,2}) + fctr::Float64 = 1.0 + if units == "degrees" + fctr = pi/180.0 + end + + theta::Float64 = 0.0 + for i = 1:length(t) + theta = thetaStart + (thetaEnd - thetaStart)*t[i] + points[i,1] = center[1] + r*cos(theta*fctr) + points[i,2] = center[2] + r*sin(theta*fctr) + end +end + +function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, + units::AbstractString, t::Float64, point::Array{Float64}) + fctr::Float64 = 1.0 + if units == "degrees" + fctr = pi/180.0 + end + theta = thetaStart + (thetaEnd - thetaStart)*t + point[1] = center[1] + r*cos(theta*fctr) + point[2] = center[2] + r*sin(theta*fctr) +end + +function endPointsLineCurvePoints(xStart::Array{Float64}, xEnd::Array{Float64}, t::Array{Float64}, points::Array{Float64}) + for i = 1:length(t) + points[i,1:2] = xStart[1:2] + t[i]*(xEnd[1:2] - xStart[1:2]) + end +end + +function endPointsLineCurvePoint(xStart::Array{Float64}, xEnd::Array{Float64}, t::Float64, point::Array{Float64}) + point[1:2] = xStart[1:2] + t*(xEnd[1:2] - xStart[1:2]) +end + +function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Float64,2}) + + argPart,eqString = keyAndValueFromString(xEqn) + xArgM = match(argRegex,argPart) + xArg = Symbol(xArgM.match) + ex = Meta.parse(eqString) + + argPart,eqString = keyAndValueFromString(yEqn) + yArgM = match(argRegex,argPart) + yArg = Symbol(yArgM.match) + ey = Meta.parse(eqString) + + for i = 1:length(t) + points[i,1] = evalWithDict(ex,Dict(xArg=> t[i])) + points[i,2] = evalWithDict(ey,Dict(yArg=> t[i])) + end +end + +function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) + + argPart,eqString = keyAndValueFromString(xEqn) + xArgM = match(argRegex,argPart) + xArg = Symbol(xArgM.match) + ex = Meta.parse(eqString) + + argPart,eqString = keyAndValueFromString(yEqn) + yArgM = match(argRegex,argPart) + yArg = Symbol(yArgM.match) + ey = Meta.parse(eqString) + + point[1] = evalWithDict(ex,Dict(xArg=> t[i])) + point[2] = evalWithDict(ey,Dict(yArg=> t[i])) + +end + +function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Array{Float64,2}) + + xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) + ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) + + sz = size(points) + nPts = sz[1] + t = 0.0 + for i = 1:nPts + t = (i-1)/(nPts-1) + points[i,1] = evalSpline(xSpline,t) + points[i,2] = evalSpline(ySpline,t) + end +end + +function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::Array{Float64}) + + xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) + ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) + + point[1] = evalSpline(xSpline,t) + point[2] = evalSpline(ySpline,t) +end + +function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) + ex = Meta.parse(s) + assignments = [:($sym = $val) for (sym,val) in locals] + eval(:(let $(assignments...); $ex; end)) +end + +function evalWithDict(ex::Expr, locals::Dict{Symbol}) + assignments = [:($sym = $val) for (sym,val) in locals] + eval(:(let $(assignments...); $ex; end)) +end + +function curvePoints(crvDict::Dict{String,Any}, N::Int) + + curveType::String = crvDict["TYPE"] + + if curveType == "PARAMETRIC_EQUATION_CURVE" + xEqn = crvDict["xEqn"] + yEqn = crvDict["yEqn"] + + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + peEquationCurvePoints(xEqn,yEqn,t,x) + elseif curveType == "END_POINTS_LINE" + xStart = realArrayForKeyFromDictionary("xStart",crvDict) + xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) + x = zeros(Float64,3,2) + t = zeros(Float64,3) + for i = 1:3 + t[i] = (i-1)/2.0 + end + + endPointsLineCurvePoints(xStart,xEnd,t,x) + elseif curveType == "CIRCULAR_ARC" + center = realArrayForKeyFromDictionary("center",crvDict) + radius = realForKeyFromDictionary("radius",crvDict) + startAngle = realForKeyFromDictionary("start angle",crvDict) + endAngle = realForKeyFromDictionary("end angle",crvDict) + units = crvDict["units"] + + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + + arcCurvePoints(center,radius,startAngle,endAngle,units,t,x) + elseif curveType == "SPLINE_CURVE" + nKnots = intForKeyFromDictionary("nKnots",crvDict) + splineData = crvDict["SPLINE_DATA"] + + M = max(N,nKnots*2) + x = zeros(Float64,M+1,2) + t = zeros(Float64,M+1) + for i = 1:M+1 + t[i] = (i-1)/M + end + + splineCurvePoints(nKnots,splineData,x) + else + + end + return x +end + +function chainPoints(chain::Array{Dict{String,Any}}, N::Int) + + x = Any[] + + for crvDict in chain + push!(x,curvePoints(crvDict,N)) + end + return x +end + +function curvePoint(crvDict::Dict{String,Any}, t::Float64) + + curveType::String = crvDict["TYPE"] + + if curveType == "PARAMETRIC_EQUATION_CURVE" + xEqn = crvDict["xEqn"] + yEqn = crvDict["yEqn"] + x = zeros(Float64,3) + peEquationCurvePoint(xEqn,yEqn,t,x) + elseif curveType == "END_POINTS_LINE" + xStart = realArrayForKeyFromDictionary("xStart",crvDict) + xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) + x = zeros(Float64,3) + endPointsLineCurvePoint(xStart,xEnd,t,x) + elseif curveType == "CIRCULAR_ARC" + center = realArrayForKeyFromDictionary("center",crvDict) + radius = realForKeyFromDictionary("radius",crvDict) + startAngle = realForKeyFromDictionary("start angle",crvDict) + endAngle = realForKeyFromDictionary("end angle",crvDict) + units = crvDict["units"] + x = zeros(Float64,3) + arcCurvePoint(center,radius,startAngle,endAngle,units,t,x) + elseif curveType == "SPLINE_CURVE" + nKnots = intForKeyFromDictionary("nKnots",crvDict) + splineData = crvDict["SPLINE_DATA"] + x = zeros(Float64,3) + splineCurvePoint(nKnots,splineData,t,x) + else + + end + return x +end + +function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}) + xFirst = curvePoint(firstCurve,1.0) + xSecond = curvePoint(secondCurve,0.0) + if maximum(abs.(xFirst - xSecond)) < 100*eps(Float64) + return true + else + return false + end +end diff --git a/HQMTool/Source/Curves/Spline.jl b/HQMTool/Source/Curves/Spline.jl new file mode 100644 index 00000000..6d34f47a --- /dev/null +++ b/HQMTool/Source/Curves/Spline.jl @@ -0,0 +1,131 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +mutable struct Spline + N::Int + x::Array{Float64} + y::Array{Float64} + b::Array{Float64} + c::Array{Float64} + d::Array{Float64} + last::Int +end + +function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) + b = zeros(Float64,N) + c = zeros(Float64,N) + d = zeros(Float64,N) + + Nm1 = N - 1 +# +# Set up tri-diagonal system +# + d[1] = x[2] - x[1] + c[2] = (y[2] - y[1])/d[1] + for i = 2:Nm1 + d[i] = x[i+1] - x[i] + b[i] = 2.0*(d[i-1] + d[i]) + c[i+1] = (y[i+1] - y[i])/d[i] + c[i] = c[i+1] - c[i] + end +# +# end conditions +# + b[1] = -d[1] + b[N] = -d[N-1] + c[1] = c[3]/(x[4] - x[2]) - c[2]/(x[3] - x[1]) + c[N] = c[N-1]/(x[N] - x[N-2]) - c[N-2]/(x[N-1] - x[N-3]) + c[1] = c[1]*d[1]^2/(x[4] - x[1]) + c[N] = -c[N]*d[N-1]^2/(x[N] - x[N-3]) +# +# Forward elimination +# + t = 0.0 + for i = 2:N + t = d[i-1]/b[i-1] + b[i] = b[i] - t*d[i-1] + c[i] = c[i] - t*c[i-1] + end +# +# Back substitution +# + c[N] = c[N]/b[N] + for ib = 1:Nm1 + i = N - ib + c[i] = (c[i] - d[i]*c[i+1])/b[i] + end +# +# Compute polynomial coefficients +# + b[N] = (y[N] - y[Nm1])/d[Nm1] + d[Nm1]*(c[Nm1] + 2.0*c[N]) + for i = 1: Nm1 + b[i] = (y[i+1] - y[i])/d[i] - d[i]*(c[i+1] + 2.0*c[i]) + d[i] = (c[i+1] - c[i])/d[i] + c[i] = 3.0*c[i] + end + c[N] = 3.0*c[N] + d[N] = d[N-1] + + spl = Spline(N,x,y,b,c,d,1) + return spl +end + +function evalSpline(spl::Spline, u::Float64) + N = spl.N + s = 0.0 + i = spl.last + + if i >= N + i = 1 + end + + if spl.x[i] < u <= spl.x[i+1] + dx = u - spl.x[i] + s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) + spl.last = i + return s + end + + i = 1 + j = N+1 + + for ii = 1:N + k = div(i+j,2) + if u < spl.x[k] + j = k + end + if u >= spl.x[k] + i = k + end + if j <= i+1 + break + end + end + dx = u - spl.x[i] + s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) + spl.last = i + return s +end \ No newline at end of file diff --git a/HQMTool/Source/Mesh/Meshing.jl b/HQMTool/Source/Mesh/Meshing.jl new file mode 100644 index 00000000..15739d62 --- /dev/null +++ b/HQMTool/Source/Mesh/Meshing.jl @@ -0,0 +1,53 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using HOHQMesh + +function generateMesh(proj::Project) +# +# Check to be sure background grid has been created (everhtying else is defaults) +# + controlDict = getControlDict(proj) + if !haskey(controlDict,"BACKGROUND_GRID") + println("A background grid is needed before meshing. Add one and try again.") + return nothing + end + path = mkpath(proj.projectDirectory) + saveProject(proj) + fileName = joinpath(proj.projectDirectory,proj.name)*".control" + mesherOutput = generate_mesh(fileName, output_directory = proj.projectDirectory) + println(mesherOutput) + postNotificationWithName(proj,"MESH_WAS_GENERATED_NOTIFICATION",(nothing,)) + return nothing +end + +function removeMesh!(proj::Project) + meshFile = getMeshFileName(proj) + rm(meshFile) + proj.xMesh = Float64[] + proj.yMesh = Float64[] + postNotificationWithName(proj,"MESH_WAS_DELETED_NOTIFICATION",(nothing,)) +end diff --git a/HQMTool/Source/Misc/DictionaryOperations.jl b/HQMTool/Source/Misc/DictionaryOperations.jl new file mode 100644 index 00000000..96bbc960 --- /dev/null +++ b/HQMTool/Source/Misc/DictionaryOperations.jl @@ -0,0 +1,89 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +#= + Some useful getters for a dictionary +=# +arrayRegex = r"(?<=\[).+?(?=\])" + +function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return parse(Float64,v) +end + +function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return parse(Int64,v) +end + +function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + return v +end + +function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + values = match(arrayRegex,v) + s = split(values.match,",") + array = [parse(Float64,s[1]),parse(Float64,s[2]),parse(Float64,s[3])] + return array +end + +function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) + v = d[key] + values = match(arrayRegex,v) + s = split(values.match,",") + array = [parse(Int,s[1]),parse(Int,s[2]),parse(Int,s[3])] + return array +end + +function keyAndValueFromString(s) + indxOfEqual = findfirst("=",s) + if indxOfEqual === nothing + return nothing + end + key = strip(s[1:indxOfEqual.start-1],[' ','\t']) + value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) + return (key,value) +end + +function showDescription(d::Dict, pre=1) + todo = Vector{Tuple}() + for (k,v) in d + if typeof(v) <: Dict + push!(todo, (k,v)) + else + println(join(fill(" ", pre)) * "$(repr(k)) => $(repr(v))") + end + end + + for (k,d) in todo + s = "$(repr(k)) => " + println(join(fill(" ", pre)) * s) + showDescription(d, pre+1+length(s)) + end + nothing +end diff --git a/HQMTool/Source/Misc/NotificationCenter.jl b/HQMTool/Source/Misc/NotificationCenter.jl new file mode 100644 index 00000000..b2ae9586 --- /dev/null +++ b/HQMTool/Source/Misc/NotificationCenter.jl @@ -0,0 +1,107 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +struct HQMNotification + sender ::Any # Who sent the notification + userInfo ::Tuple # Any necessary data needed +end + +struct HQMNotificationObject + observer::Any + fcn ::Any +end + +HQMNotificationCenter = Dict{String,Vector{HQMNotificationObject}}() +HQMNotificationsON = true + +""" + addObserver(observer::Any, note::String, fnction::Any) + +fnction is the function to be executed (called) when a +notification of name `note` is given. + +The function called upon notification must have the signature +fnction(observer, sender, args...) +""" +function addObserver(observer::Any, note::String, fnction::Any) + + noteObj = HQMNotificationObject(observer,fnction) + if !haskey(HQMNotificationCenter,note) + HQMNotificationCenter[note] = HQMNotificationObject[] + end + push!(HQMNotificationCenter[note],noteObj) +end +""" + unRegisterForNotification(observer::Any, note::String) + +Remove the observer from being notified by the notification `note` +""" +function unRegisterForNotification(observer::Any, note::String) + if haskey(HQMNotificationCenter,note) + global observers = HQMNotificationCenter[note] + + for i = 1:length(observers) + global noteObj = observers[i] + noteObserver = noteObj.observer + if noteObserver === observer + deleteat!(observers,i) + break + end + end + if isempty(observers) + delete!(HQMNotificationCenter,note) + end + end +end +""" + postNotificationWithName(sender::Any, name::String, userInfo::Tuple) + +Executes the function associated with the observer for the notification `note` +""" +function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) + if haskey(HQMNotificationCenter,note) && HQMNotificationsON + global observers = HQMNotificationCenter[note] + + for i = 1:length(observers) + global noteObj = observers[i] + f = noteObj.fcn + observer = noteObj.observer + if isnothing(userInfo[1]) + f(observer,sender) + else + f(observer,sender,userInfo...) + end + end + end +end + +function enableNotifications() + global HQMNotificationsON = true +end + +function disableNotifications() + global HQMNotificationsON = false +end diff --git a/HQMTool/Source/Model/Geometry.jl b/HQMTool/Source/Model/Geometry.jl new file mode 100644 index 00000000..71a99954 --- /dev/null +++ b/HQMTool/Source/Model/Geometry.jl @@ -0,0 +1,93 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +const TOP = 1; const LEFT = 2; const BOTTOM = 3; const RIGHT = 4 + +""" +curveBounds(crvPoints::Array{Float64,2}) + +Find the bounds of a single curve, discretized as an array +""" +function curveBounds(crvPoints::Array{Float64,2}) + + s = size(crvPoints) + top = -Inf64 + left = Inf64 + bottom = Inf64 + right = -Inf64 + + for i = 1:s[1] + right = max(right,crvPoints[i,1]) + left = min(left,crvPoints[i,1]) + top = max(top,crvPoints[i,2]) + bottom = min(bottom,crvPoints[i,2]) + end + + bounds = zeros(Float64,4) + bounds[TOP] = top + bounds[LEFT] = left + bounds[BOTTOM] = bottom + bounds[RIGHT] = right + + return bounds +end + +function chainBounds(chain::Array{Any}) + bounds = emptyBounds() + for crv in chain + crvBounds = curveBounds(crv) + bounds = bboxUnion(bounds,crvBounds) + end + return bounds +end + +""" + bboxUnion(box1::Array{Float64}, box2::Array{Float64}) + +Returns the union of two bounding boxes +""" +function bboxUnion(box1::Array{Float64}, box2::Array{Float64}) + union = zeros(Float64,4) + union[TOP] = max(box1[TOP] ,box2[TOP]) + union[LEFT] = min(box1[LEFT] ,box2[LEFT]) + union[BOTTOM] = min(box1[BOTTOM],box2[BOTTOM]) + union[RIGHT] = max(box1[RIGHT] ,box2[RIGHT]) + + return union +end +""" + +Returns an array that will always be ignored when unioned with +another bounding box. +""" +function emptyBounds() + emptee = zeros(Float64,4) + emptee[TOP] = -Inf64 + emptee[LEFT] = Inf64 + emptee[BOTTOM] = Inf64 + emptee[RIGHT] = -Inf64 + return emptee +end diff --git a/HQMTool/Source/Project/BackgroundGridAPI.jl b/HQMTool/Source/Project/BackgroundGridAPI.jl new file mode 100644 index 00000000..687038af --- /dev/null +++ b/HQMTool/Source/Project/BackgroundGridAPI.jl @@ -0,0 +1,265 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addBackgroundGrid(proj::Project, bgSize::Array{Float64}) + +Add the background grid block with the grid size to be a 3-vector. Use this when there +is an outer boundary defined in the model. +""" +function addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + disableUndo() + disableNotifications() + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + setBackgroundGridSize!(proj, bgSize, "background grid size") + enableUndo() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + enableNotifications() + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) + +Add the background grid block with bounding box = [TOP, LEFT, BOTTOM, RIGHT] +and the number of intervals in each diredction. Use this when there +is _no_ outer boundary defined in the model. +""" +function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + disableUndo() + disableNotifications() + proj.bounds = box + proj.userBounds = deepcopy(box) + + dx = zeros(Float64,3) + dx[1] = (box[RIGHT] - box[LEFT])/N[1] + dx[2] = (box[TOP] - box[BOTTOM])/N[2] + + setBackgroundGridSize!(proj, dx, "dx") + setBackgroundGridLowerLeft!(proj,[box[LEFT], box[BOTTOM], 0.0]) + setBackgroundGridSteps!(proj,N) + enableUndo() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + enableNotifications() + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + +Add the background grid block using the left corner, x0, the +grid size dx, and the number of intervals in each direction. Use this when there +is _no_ outer boundary defined in the model. This version mimics HOHQMesh's +backgroundGrid block, but the version + + addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) + +is a lot easier to use. + +TODO: Change HOHQMesh and delete this way to specify the domain and use the bounding box one instead. + +""" +function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + disableUndo() + disableNotifications() + setBackgroundGridSize!(proj, dx, "dx") + setBackgroundGridLowerLeft!(proj,x0) + setBackgroundGridSteps!(proj,N) + proj.userBounds[TOP] = x0[2] + N*dx[2] + proj.userBounds[LEFT] = x0[1] + proj.userBounds[BOTTOM] = x0[2] + proj.userBounds[RIGHT] = x0[1] + N*dx[1] + enableUndo() + enableNotifications() + registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + removeBackgroundGrid!(proj::Project) + +Remove the background grid block from the project. +""" +function removeBackgroundGrid!(proj::Project) + cDict = getControlDict(proj) + registerWithUndoManager(proj,addBackgroundGrid!,(cDict,),"Delete Background Grid") + delete!(cDict,"RUN_PARAMETERS") + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + setBackgroundGridSpacing!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + +User facing function +""" +function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + newSize = [dx,dy] + if haskey(bgDict,"dx") + oldSpacing = realArrayForKeyFromDictionary("dx", bgDict) + setBackgroundGridSize!(proj, newSize, "dx") + # With the "corner+intervals" setting of the outer boundary deprecated, keep + # the original bounds fixed. + x0 = realArrayForKeyFromDictionary("x0",bgDict) + Nx = round(Int,(proj.userBounds[RIGHT] - proj.userBounds[LEFT]) /dx[1]) + Ny = round(Int,(proj.userBounds[TOP] - proj.userBounds[BOTTOM])/dx[2]) + N = [Nx,Ny,0] + disableNotifications() + setBackgroundGridSteps!(proj,N) + enableNotifications() + else + oldSpacing = realArrayForKeyFromDictionary("background grid size", bgDict) + setBackgroundGridSize!(proj, newSize, "background grid size") + end + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + registerWithUndoManager(proj,setBackgroundGridSize!, + (oldSpacing[1],oldSpacing[2],0.0),"Set Background Grid Spacing") + return nothing + end +""" + getBackgroundGridSize(proj::Project) + +Returns the background grid size array. +""" +function getBackgroundGridSize(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"dx") + return realArrayForKeyFromDictionary("dx",bgDict) + elseif haskey(bgDict,"background grid size") + return realArrayForKeyFromDictionary("background grid size",bgDict) + else + return nothing + end +end +""" + function getBackgroundGridLowerLeft(proj::Project) + +Returns the [x,y] of the lower left point of thebackground grid. +""" +function getBackgroundGridLowerLeft(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"x0") + return realArrayForKeyFromDictionary("x0",bgDict) + else + return nothing + end +end +""" + function getBackgroundGridLowerLeft(proj::Project) + +Returns the [x,y,z] of the lower left point of thebackground grid. +""" +function getBackgroundGridSteps(proj::Project) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + if haskey(bgDict,"N") + return realIntForKeyFromDictionary("N",bgDict) + else + return nothing + end +end +""" + setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + +Set the lower left location of the background grid for problems that have no +outer boundary. +""" +function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,"x0") + oldLowerLeft = realArrayForKeyFromDictionary("x0",bgDict) + registerWithUndoManager(proj,setBackgroundGridLowerLeft!, + (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") + end + + x0Str = @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) + bgDict["x0"] = x0Str + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end +""" +setBackgroundGridSteps!(proj::Project, N::Array{Int}) + +Set how many steps of size setBackgroundGridSpacing in each direction the background grid extends from the +lower left. +""" +function setBackgroundGridSteps!(proj::Project, N::Array{Int}) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,"N") + oldN = intArrayForKeyFromDictionary("N",bgDict) + registerWithUndoManager(proj,setBackgroundGridSteps!, + (oldN[1],oldN[2],oldN[3]),"Set Background Steps") + end + + NStr = @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) + bgDict["N"] = NStr + + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end +""" +setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) +""" +function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + setBackgroundGridSize!(proj, dx[1], dx[2], key) + return nothing +end +""" +setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) +""" +function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) + bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") + + if haskey(bgDict,key) + oldDx = realArrayForKeyFromDictionary(key,bgDict) + registerWithUndoManager(proj,setBackgroundGridSize!, + (oldDx[1],oldDx[2],oldDx[3]),"Set Background Size") + end + + dxStr = @sprintf("[%f,%f,%f]", dx, dy, 0.0) + bgDict[key] = dxStr + postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) + return nothing +end + +""" + addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) + +Used only for undo/redo. +""" +function addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) + controlDict = getControlDict(proj) + controlDict["BACKGROUND_GRID"] = dict + return nothing +end + diff --git a/HQMTool/Source/Project/ControlInputAPI.jl b/HQMTool/Source/Project/ControlInputAPI.jl new file mode 100644 index 00000000..33ec96e4 --- /dev/null +++ b/HQMTool/Source/Project/ControlInputAPI.jl @@ -0,0 +1,60 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +function getControlDict(proj::Project) + if haskey(proj.projectDictionary,"CONTROL_INPUT") + return proj.projectDictionary["CONTROL_INPUT"] + else + controlDict = Dict{String,Any}() + proj.projectDictionary["CONTROL_INPUT"] = controlDict + controlDict["TYPE"] = "CONTROL_INPUT" + return controlDict + end +end + +function getDictInControlDictNamed(proj::Project,name::String) + controlDict = getControlDict(proj) + + if haskey(controlDict,name) + return controlDict[name] + else + d = Dict{String,Any}() + controlDict[name] = d + d["TYPE"] = name + return d + end +end + +function getListInControlDictNamed(proj::Project,name::String) + dict = getDictInControlDictNamed(proj::Project,name::String) + if haskey(dict,"LIST") + return dict["LIST"] + else + lst = [] + dict["LIST"] = lst + return lst + end +end diff --git a/HQMTool/Source/Project/CurvesAPI.jl b/HQMTool/Source/Project/CurvesAPI.jl new file mode 100644 index 00000000..090e56d5 --- /dev/null +++ b/HQMTool/Source/Project/CurvesAPI.jl @@ -0,0 +1,450 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + +Creates and returns a new parametricEquationCurve in the form of a Dictionary +""" +function newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + + crv = Dict{String,Any}() + crv["TYPE"] = "PARAMETRIC_EQUATION_CURVE" + disableNotifications() + disableUndo() + setCurveName!(crv,name) + setXEqn!(crv,xEqn) + setYEqn!(crv,yEqn) + setZEqn!(crv,zEqn) + enableUndo() + enableNotifications() + return crv +end +""" + newEndPointsLineCurve(name::String, xStart::Array{Float64},xEnd::Array[Float64]) + +Creates and returns a new curve defined by its end points in the form of a Dictionary +""" +function newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + crv = Dict{String,Any}() + crv["TYPE"] = "END_POINTS_LINE" + disableNotifications() + disableUndo() + setCurveName!(crv,name) + setStartPoint!(crv,xStart) + setEndPoint!(crv,xEnd) + enableNotifications() + enableUndo() + return crv +end +""" + newCircularArcCurve(name::String, center::Array{Float64}, + startAngle::Float64, endAngle::Float64, + units::String) + +Creates and returns a new circular arc curve in the form of a Dictionary +""" +function newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String = "degrees") + + arc = Dict{String,Any}() + arc["TYPE"] = "CIRCULAR_ARC" + disableNotifications() + disableUndo() + setCurveName!(arc,name) + setArcUnits!(arc,units) + setArcCenter!(arc,center) + setArcStartAngle!(arc,startAngle) + setArcEndAngle!(arc,endAngle) + setArcRadius!(arc,radius) + enableNotifications() + enableUndo() + return arc +end +""" + newSplineCurve(name::String, nKnots::Int, data::Array{Float64,4}) + +Returns a spline curve given the number of knots and the array of knots. +""" +function newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + spline = Dict{String,Any}() + spline["TYPE"] = "SPLINE_CURVE" + disableNotifications() + disableUndo() + setCurveName!(spline,name) + setSplineNKnots!(spline,nKnots) + setSplinePoints!(spline,data) + enableNotifications() + enableUndo() + return spline +end +""" + newSplineCurve(name::String, dataFile::String) + +Returns a spline curve given a data file that contains the number of knots +on the first line, and the spline data following that. +""" +function newSplineCurve(name::String, dataFile::String) + + spline = Dict{String,Any}() + open(dataFile,"r") do f + nKnots = parse(Int,readline(f)) + splineDataArray = zeros(Float64,nKnots,4) + for i = 1:nKnots + currentLine = split(readline(f)) + for j = 1:4 + splineDataArray[i,j] = parse(Float64,currentLine[j]) + end + end + spline = newSplineCurve(name, nKnots, splineDataArray) + end + return spline +end +""" + duplicateCurve(crv::Dict{String,Any}, newName::String) + +Duplicate the given curve giving it the new name. +""" +function duplicateCurve(crv::Dict{String,Any}, newName::String) + disableNotifications() + disableUndo() + + duplicate = deepcopy(crv) + setCurveName!(duplicate,newName) + + enableNotifications() + enableUndo() + return duplicate +end +""" + setCurveName!(curveDict, name) + +Set the name of the curve represented by curveDict. +""" +function setCurveName!(crv::Dict{String,Any}, name::String) + if haskey(crv,"name") + oldName = crv["name"] + registerWithUndoManager(crv,setCurveName!, (oldName,), "Set Curve Name") + postNotificationWithName(crv,"CURVE_DID_CHANGE_NAME_NOTIFICATION",(oldName,)) + end + crv["name"] = name +end +""" + getCurveName(crv::Dict{String,Any}) +""" +function getCurveName(crv::Dict{String,Any}) + return crv["name"] +end +""" + getCurveType(crv::Dic{String,Any}) + + Get the type of the curve, `END_POINTSLINE_CURVE`, `PARAMETRIC_EQUATION_CURVE`, + `SPLINE_CURVE`, or `CIRCULAR_ARC` as a string. +""" +function getCurveType(crv::Dict{String,Any}) + return crv["TYPE"] +end +""" + setXEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the x-equation. +""" +function setXEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"xEqn") + oldEqn = crv["xEqn"] + registerWithUndoManager(crv,setXEqn!, (eqn,), "Set X Equation") + end + crv["xEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getXEqn(crv::Dict{String,Any}) +""" +function getXEqn(crv::Dict{String,Any}) + if(haskey(crv,"xEqn")) + return crv["xEqn"] + end + return nothing +end +""" + setYEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the y-equation. +""" +function setYEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"yEqn") + oldEqn = crv["yEqn"] + registerWithUndoManager(crv,setYEqn!, (eqn,), "Set Y Equation") + end + crv["yEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getYEqn(crv::Dict{String,Any}) +""" +function getYEqn(crv::Dict{String,Any}) + if(haskey(crv,"yEqn")) + return crv["yEqn"] + end + return nothing +end +""" + setZEqn!(parametricEquationCurve, eqn) + +For a parametric equation, set the zEqn-equation. +""" +function setZEqn!(crv::Dict{String,Any}, eqn::String) + if haskey(crv,"zEqn") + oldEqn = crv["zEqn"] + registerWithUndoManager(crv,setZEqn!, (eqn,), "Set Z Equation") + end + crv["zEqn"] = eqn + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getZEqn(crv::Dict{String,Any}) +""" +function getZEqn(crv::Dict{String,Any}) + if(haskey(crv,"zEqn")) + return crv["zEqn"] + end + return nothing +end +""" + setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the start point for a line curve. +""" +function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + key = "xStart" + if haskey(crv,key) + oldPt = crv[key] + registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") + end + crv[key] = pStr + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) + crv["xStart"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getStartPoint(crv::Dict{String,Any}, point::Array{Float64}) + +Get the start point for a line curve as an array +""" +function getStartPoint(crv::Dict{String,Any}) + return realArrayForKeyFromDictionary("xStart",crv) +end +""" + setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the end point for a line curve. +""" +function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + key = "xEnd" + if haskey(crv,key) + oldPt = crv[key] + registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") + end + crv[key] = pStr + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) + crv["xEnd"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getEndPoint(crv::Dict{String,Any}, point::Array{Float64}) + +Get the end point for a line curve as an array. +""" +function getEndPoint(crv::Dict{String,Any}) + return realArrayForKeyFromDictionary("xEnd",crv) +end +""" + setArcUnits(crv::Dict{String,Any}, units::String) + +Set the units for the start and end angles of a circular arc curve. +""" +function setArcUnits!(arc::Dict{String,Any}, units::String) + if units == "degrees" || units == "radians" + key = "units" + if haskey(arc,key) + oldUnits = arc[key] + registerWithUndoManager(arc,setArcUnits!, (oldUnits,), "Set Arc Units") + end + arc[key] = units + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) + else + println("Units must either be `degrees` or `radians`. Try setting `units` again.") + end +end +""" + getArcUnits(crv::Dict{String,Any}, units::String) + +Get the units for the start and end angles of a circular arc curve. +""" +function getArcUnits!(arc::Dict{String,Any}) + return arc["units"] +end +""" + setArcCenter!(crv::Dict{String,Any}, point::Array{Float64}) + +Set the center of a circular arc. +""" +function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + key = "center" + if haskey(arc,key) + oldVal = arc[key] + registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") + end + + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + arc[key] = pStr + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) + arc["center"] = pointAsString + postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcCenter(crv::Dict{String,Any}, point::Array{Float64}) + +Get the center of a circular arc as an array +""" +function getArcCenter(arc::Dict{String,Any}) + return realArrayForKeyFromDictionary("center",arc) +end +""" + setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + + """ +function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + key = "start angle" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcStartAngle!, (oldVal,), "Set Arc Start Angle") + end + arc[key] = string(angle) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcStartAngle(arc::Dict{String,Any}, angle::Float64) + + """ +function getArcStartAngle(arc::Dict{String,Any}) + return parse(Float64,arc["start angle"]) +end +""" + setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + + """ +function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + key = "end angle" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcEndAngle!, (oldVal,), "Set Arc Start Angle") + end + arc[key] = string(angle) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcEndAngle(arc::Dict{String,Any}, angle::Float64) + + """ +function getArcEndAngle(arc::Dict{String,Any}) + return parse(Float64,arc["end angle"]) +end +""" + setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + """ +function setArcRadius!(arc::Dict{String,Any}, radius::Float64) + key = "radius" + if haskey(arc,key) + oldVal = parse(Float64,arc[key]) + registerWithUndoManager(arc,setArcRadius!, (oldVal,), "Set Arc Radius") + end + arc[key] = string(radius) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getArcRadius(arc::Dict{String,Any}, radius::Float64) + +""" +function getArcRadius(arc::Dict{String,Any}) + return parse(Float64,arc["radius"]) +end +""" + setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) +""" +function setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) + key = "nKnots" + if haskey(spline,key) + oldVal = parse(Int,spline[key]) + registerWithUndoManager(spline,setSplineNKnots!, (oldVal,), "Set Spline Knots") + end + spline["nKnots"] = string(nKnots) + postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getSplineNKnots(spline::Dict{String,Any}) +""" +function getSplineNKnots(spline::Dict{String,Any}) + return parse(Int,spline["nKnots"]) +end +""" + setSplinePoints!(spline::Dict{String,Any},points::Array{Float64,4}) +""" +function setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) + key = "SPLINE_DATA" + if haskey(spline,key) + registerWithUndoManager(spline,setSplinePoints!, (spline["SPLINE_DATA"],), "Set Spline Points") + end + spline["SPLINE_DATA"] = points + postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + getSplinePoints(spline::Dict{String,Any}) +""" +function getSplinePoints(spline::Dict{String,Any}) + return spline["SPLINE_DATA"] +end diff --git a/HQMTool/Source/Project/Generics.jl b/HQMTool/Source/Project/Generics.jl new file mode 100644 index 00000000..c8976072 --- /dev/null +++ b/HQMTool/Source/Project/Generics.jl @@ -0,0 +1,164 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +# +# Creating curves +# +""" + new(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + +Create a new parametric equation curve. +""" +function new(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + return newParametricEquationCurve(name, xEqn, yEqn, zEqn) +end + +""" + new(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + +Create a new line defined by its end points. +""" +function new(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + return newEndPointsLineCurve(name, xStart, xEnd) +end + +""" + new(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) + +Create a new circular arc. +""" +function new(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String = "degrees") + return newCircularArcCurve(name,center,radius,startAngle,endAngle,units) +end + +""" + new(name::String, dataFile::String) + +Create a spline curve from the contents of a data file. +""" +function new(name::String, dataFile::String) + return newSplineCurve(name, dataFile) +end + +""" + new(name::String, nKnots::Int, data::Matrix{Float64}) + +Create a spline curve from an array of knots +""" +function new(name::String, nKnots::Int, data::Matrix{Float64}) + return newSplineCurve(name, nKnots, data) +end +# +# Adding curves to a model +# +""" + add!(proj::Project, obj::Dict{String,Any}) + +Add a curve to the outer boundary or a refinement reion to +the project +""" +function add!(proj::Project, obj::Dict{String,Any}) + if obj["TYPE"] == "REFINEMENT_CENTER" || obj["TYPE"] == "REFINEMENT_LINE" + addRefinementRegion!(proj, obj) + else + addCurveToOuterBoundary!(proj, obj) + end +end + +""" + add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + +Add a curve to the inner boundary named `boundaryName`. +""" +function add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + addCurveToInnerBoundary!(proj, crv, boundaryName) +end + +""" +get(proj::Project, curveName::String) + +Get the curve with name `curveName` from the outer boundary. +""" +function get(proj::Project, curveName::String) + return getOuterBoundaryCurveWithName(proj, curveName) +end + +""" + get(proj::Project, curveName::String, boundaryName::String) + +Get the curve named `curveName` from the inner boundary named `boundaryName` +""" +function get(proj::Project, curveName::String, boundaryName::String) + return getInnerBoundaryCurve(proj, curveName, boundaryName) +end + +""" + getInnerBoundary(proj::Project, name::String) + +Get the chain of curves from the inner boundary with name `name`. +""" +function getInnerBoundary(proj::Project, name::String) + return getInnerBoundaryChainWithName(proj, name) +end + +""" + remove!(proj::Project, curveName::String) + +Delete the curve named curveName from the outer boundary +""" +function remove!(proj::Project, curveName::String) + removeOuterBoundaryCurveWithName!(proj, curveName) +end + +""" + remove!(proj::Project, curveName::String, innerBoundaryName::String) + +Delete the curve named curveName from the inner boundary named innerBoundaryName +""" +function remove!(proj::Project, curveName::String, innerBoundaryName::String) + removeInnerBoundaryCurve!(proj, curveName, innerBoundaryName) +end + diff --git a/HQMTool/Source/Project/ModelAPI.jl b/HQMTool/Source/Project/ModelAPI.jl new file mode 100644 index 00000000..336f70ae --- /dev/null +++ b/HQMTool/Source/Project/ModelAPI.jl @@ -0,0 +1,427 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +include("../Model/Geometry.jl") + +# +# -------------------------------------------------------------------------------------- +# +""" + addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + +Add a curve to the outer boundary. The curves must be added in order counter-clockwise +""" +function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + chain = getOuterBoundaryChainList(proj) +# +# Check if the new curve meets the last one added +# + if !isempty(chain) + lastCurve = last(chain) + if !curvesMeet(lastCurve,crv) + lastName = getCurveName(lastCurve) + newName = getCurveName(crv) + println("the curve $lastName does not meet the previous curve, $newName. Try again.") + return + end + end +# +# Checks out, add to model +# + push!(chain,crv) + crvPoints = curvePoints(crv,defaultPlotPts) + push!(proj.outerBndryPoints, crvPoints) + proj.backgroundGridShouldUpdate = true + + push!(proj.outerBndryNames,crv["name"]) + + enableUndo() + registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") + enableNotifications() + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + removeOuterBoundaryCurveWithName!(proj::Project, name::String) + +Remove the named curve in the outer boundary +""" +function removeOuterBoundaryCurveWithName!(proj::Project, name::String) + lst = getOuterBoundaryChainList(proj) + indx = getChainIndex(lst,name) + if indx > 0 + removeOuterBoundaryCurveAtIndex(proj,indx) # posts undo/notification + proj.backgroundGridShouldUpdate = true + end +end +""" + getOuterBoundaryCurveWithName(proj::Project, name::String) +""" +function getOuterBoundaryCurveWithName(proj::Project, name::String) + lst = getOuterBoundaryChainList(proj) + for crv in lst + if crv["name"] == name + return crv + end + end +end +""" + insertOuterBoundaryCurveAtIndex(proj::Project, crv::Dict{String,Any}, indx::Int) + +Insert a curve at the specified index. +""" +function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) + lst = getOuterBoundaryChainList(proj) + insert!(lst,indx,crv) + insert!(proj.outerBndryPoints,indx,curvePoints(crv,defaultPlotPts)) + insert!(proj.outerBndryNames,indx,crv["name"]) + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end + +function removeOuterBoundaryCurveAtIndex(proj::Project, indx::Int) + lst = getOuterBoundaryChainList(proj) + crv = lst[indx] + deleteat!(lst,indx) + deleteat!(proj.outerBndryNames,indx) + deleteat!(proj.outerBndryPoints,indx) + proj.backgroundGridShouldUpdate = true + enableNotifications() + enableUndo() + registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Add Curve") + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + addOuterBoundary!(proj::Project) + +Add an empty outer boundary to the project. There can be only one. +""" +function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) + model = getModelDict(proj) + model["OUTER_BOUNDARY"] = outerBoundary + registerWithUndoManager(proj,removeOuterboundary!, (nothing,), "Add Outer Boundary") +end +""" + removeOuterboundary!(proj::Project) + +Remove the outer boundary curve if it exists. +""" +function removeOuterboundary!(proj::Project) + modelDict = getModelDict(proj) + if haskey(modelDict,"OUTER_BOUNDARY") + ob = modelDict["OUTER_BOUNDARY"] + enableUndo() + registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") + delete!(modelDict,"OUTER_BOUNDARY") + proj.outerBndryPoints = Any[] + proj.outerBndryNames = String[] + proj.backgroundGridShouldUpdate = true + enableNotifications() + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) + end +end + +function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) + modelDict = getModelDict(proj) + modelDict["OUTER_BOUNDARY"] = obDict +end +# +# -------------------------------------------------------------------------------------- +# +""" + getOuterBoundary(proj::Project) + +Get the array of outer boundary curves. +""" +function getOuterBoundaryChainList(proj::Project) + outerBndryDict = getDictInModelDictNamed(proj,"OUTER_BOUNDARY") + if haskey(outerBndryDict,"LIST") + lst = outerBndryDict["LIST"] + return lst + else + lst = Dict{String,Any}[] + outerBndryDict["LIST"] = lst + return lst + end +end +# +# -------------------------------------------------------------------------------------- +# INNER BOUNDARY FUNCTIONS +# -------------------------------------------------------------------------------------- +# +""" + addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + +Add a curve to the inner boundary with name `boundaryName`. If an inner boundary of that name +does not exist, one is created. +""" +function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + curveList = chain["LIST"] +# +# Check if the new curve meets the last one added +# + if !isempty(curveList) + lastCurve = last(curveList) + if !curvesMeet(lastCurve,crv) + lastName = getCurveName(lastCurve) + newName = getCurveName(crv) + println("the curve $lastName does not meet the previous curve, $newName. Try again.") + return + end + end +# +# Checks out, add to model +# + push!(curveList,crv) + + if i > length(proj.innerBoundaryPoints) # New inner boundary chain + a = [] + push!(a,curvePoints(crv,defaultPlotPts)) + push!(proj.innerBoundaryPoints,a) + else + a = proj.innerBoundaryPoints[i] + push!(a,curvePoints(crv,defaultPlotPts)) + end + push!(proj.innerBoundaryNames[i],crv["name"]) + proj.backgroundGridShouldUpdate = true + registerWithUndoManager(proj,removeInnerBoundaryCurve!, + (crv["name"],boundaryName), + "Add Inner Boundary Curve") + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + removeInnerBoundaryCurve!(proj::Project, name::String) + +Remove the named curve in the outer boundary +""" +function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + i, chain = getInnerBoundaryChainWithName(proj,chainName) + lst = chain["LIST"] + if isempty(lst) + println("No curve ", name, " in boundary ", chainName) #TODO Replace with error() + return + end + indx = getChainIndex(lst,name) + removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) +end + +function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, + indx::Int, boundaryName::String) + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + lst = chain["LIST"] + insert!(lst,indx,crv) + innerBoundaryPoints = proj.innerBoundaryPoints[i] + insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) + insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end + +function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) + i, chain = getInnerBoundaryChainWithName(proj,chainName) + lst = chain["LIST"] + if indx > 0 + crv = lst[indx] + deleteat!(lst,indx) + deleteat!(proj.innerBoundaryNames[i],indx) + deleteat!(proj.innerBoundaryPoints[i],indx) + registerWithUndoManager(proj,insertInnerBoundaryCurveAtIndex!, + (crv,indx,chainName), + "Remove Inner Boundary Curve") + if isempty(lst) + ibChains = getAllInnerBoundaries(proj) + deleteat!(ibChains,i) + deleteat!(proj.innerBoundaryChainNames,i) + deleteat!(proj.innerBoundaryPoints,i) + end + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) + end +end +""" + removeInnerBoundary!(proj::Project, chainName::String) + +Remove an entire inner boundary +""" +function removeInnerBoundary!(proj::Project, chainName::String) + i,crv = getInnerBoundaryChainWithName(p,chainName) + deleteat!(proj.innerBoundaryChainNames,i) + deleteat!(proj.innerBoundaryPoints,i) + ibChains = getAllInnerBoundaries(proj) + deleteat!(ibChains,i) +end +# +# -------------------------------------------------------------------------------------- +# +""" + addInnerBoundaryWithName!(proj::Project,name::String) + +Create a new empty inner boundary with the given name. +""" +function addInnerBoundaryWithName!(proj::Project,name::String) +# +# Create a new chain +# + bndryChain = Dict{String,Any}() + bndryChain["name"] = name + bndryChain["TYPE"] = "CHAIN" + bndryCurves = Dict{String,Any}[] + bndryChain["LIST"] = bndryCurves + + innerBoundariesList = getAllInnerBoundaries(proj) + push!(innerBoundariesList,bndryChain) +# +# Prepare for plotting +# + push!(proj.innerBoundaryChainNames,name) + componentNames = String[] + push!(proj.innerBoundaryNames,componentNames) + + return bndryChain +end +# +#---------------------------------------------------------------------------------------- +# +function getChainIndex(chain::Vector{Dict{String, Any}},name) + for (i,dict) in enumerate(chain) + if dict["name"] == name + return i + end + end + return 0 +end +""" + getAllInnerBoundaries(proj::Project) + +Returns an array of the inner boundaries +""" +# +# -------------------------------------------------------------------------------------- +# +function getAllInnerBoundaries(proj::Project) + innerBndryDict = getDictInModelDictNamed(proj,"INNER_BOUNDARIES") + if haskey(innerBndryDict,"LIST") + lst = innerBndryDict["LIST"] + return lst + else + lst = [] + innerBndryDict["LIST"] = lst + return lst + end + return nothing +end +# +# -------------------------------------------------------------------------------------- +# +""" + getInnerBoundaryWithName(proj::Project, name::String) + +Get the inner boundary CHAIN with the given name. If one does not exist, it +is created. +""" +function getInnerBoundaryChainWithName(proj::Project, name::String) + lst = getAllInnerBoundaries(proj::Project) + # + # See if there is an inner boundary with that name + # + l = length(lst) + i = 1 + if l > 0 + for chain in lst + bCurveName = chain["name"] + if bCurveName == name + return i, chain + i = i + 1 + end + end + end + # + # If not, create one + # + chain = addInnerBoundaryWithName!(proj,name) + return l+1, chain +end +""" + +""" +function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + lst = chain["LIST"] + for crv in lst + if crv["name"] == curveName + return crv + end + end + return nothing +end +""" + innerBoundaryIndices(proj::Project, curveName::String) + +Returns (curveIndex,chainIndex) for the location of the curve named `curveName` +in it's inner boundary chain. +""" +function innerBoundaryIndices(proj::Project, curveName::String) +# +# For each inner boundary curve chain +# + chains = getAllInnerBoundaries(proj) + for (j,chain) in enumerate(chains) + crvList = chain["LIST"] + for (i,crv) in enumerate(crvList) + if crv["name"] == curveName + return i,j + end + end + end + return (0,0) +end +# +# -------------------------------------------------------------------------------------- +# +function getModelDict(proj::Project) + if haskey(proj.projectDictionary,"MODEL") + return proj.projectDictionary["MODEL"] + else + modelDict = Dict{String,Any}() + proj.projectDictionary["MODEL"] = modelDict + modelDict["TYPE"] = "MODEL" + return modelDict + end +end + +function getDictInModelDictNamed(proj::Project,name::String) + modelDict = getModelDict(proj) + + if haskey(modelDict,name) + return modelDict[name] + else + d = Dict{String,Any}() + modelDict[name] = d + d["TYPE"] = name + return d + end +end diff --git a/HQMTool/Source/Project/Project.jl b/HQMTool/Source/Project/Project.jl new file mode 100644 index 00000000..98fd4428 --- /dev/null +++ b/HQMTool/Source/Project/Project.jl @@ -0,0 +1,409 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# +#= + The Project is the controller in an MVC paradigm. It manages the model, + stored in the projectDictionary, and plotting data, and responds to enableNotifications + of changes. +=# +mutable struct Project + name::String + projectDirectory:: String + projectDictionary::Dict{String,Any} + plt::Any #For the plot + plotOptions::Int # = combinations of MODEL, GRID, MESH +# +# For drawing +# + outerBndryPoints ::Array{Any} # CHAIN + outerBndryNames ::Array{String} + innerBoundaryPoints ::Array{Any} # Array of CHAINs + innerBoundaryNames ::Array{Any} # Array of CHAINs of names + innerBoundaryChainNames::Array{String} # Array of the names of the CHAINs + refinementRegionPoints ::Array{Array{Float64,2}} # Array of Array of points + refinementRegionNames ::Array{String} + refinementRegionLoc ::Array{Array{Float64}} # Center point of a refinement region + bounds ::Array{Float64} + userBounds ::Array{Float64} + xGrid ::Array{Float64} + yGrid ::Array{Float64} + xMesh ::Array{Float64} + yMesh ::Array{Float64} + backgroundGridShouldUpdate::Bool + meshShouldUpdate ::Bool +end + +defaultPlotPts = 50 +meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) +plotFileFormats = Set(["sem", "skeleton"]) +smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) +statusValues = Set(["ON", "OFF"]) +refinementTypes = Set(["smooth", "sharp"]) + +include("./ControlInputAPI.jl") +include("./BackgroundGridAPI.jl") +include("./ModelAPI.jl") +include("./RefinementRegionsAPI.jl") +include("./RunParametersAPI.jl") +include("./SmootherAPI.jl") + +""" + openProject(fileName::String, folder::String) + +Open existing project described in the control File. + + folder = folder the control file is in + fileNmae = the name of the file +""" +function openProject(fileName::String, folder::String) + + controlFile = joinpath(folder,fileName) + splitName = split(fileName,".") + + controlDict = ImportControlFile(controlFile) + + s = string(splitName[1]) # This is dumb + proj = newProject(s,folder) +# +# Overwrite defaults +# + proj.projectDictionary = controlDict + + assemblePlotArrays(proj) + clearUndoRedo() + + return proj +end +""" + saveProject(proj::Project) + + proj = Project to be saved +Save a project dictionary to the file path specified when the project was created. +""" +function saveProject(proj::Project) + getfolder = mkpath(proj.projectDirectory) + fileName = joinpath(proj.projectDirectory,proj.name)*".control" + WriteControlFile(proj.projectDictionary,fileName) +end +""" + newProject(name::String, folder::String) + +Create a new project with the given name. That name will be used +for the mesh and plot files in the specified folder. +""" +function newProject(name::String, folder::String) + ibChainPoints = Any[] + ibChainNames = String[] + ibNames = Any[] + obNames = String[] + obPnts = Any[] + projectDict = Dict{String,Any}() + plt = nothing + undoStack = Any[] + redoStack = Any[] + bounds = emptyBounds() # top, left, bottom, right + userBounds = emptyBounds() + xGrid = Float64[] + yGrid = Float64[] + xMesh = Float64[] + yMesh = Float64[] + refinementRegionPts = Array{Array{Float64,2}}[] + refinementRegionNames = Array{String}[] + refinementRegionLocs = Array{Array{Float64}}[] + plotOptions = 0 +# + proj = Project(name, folder, projectDict, plt, plotOptions, obPnts, obNames, + ibChainPoints,ibNames, ibChainNames, + refinementRegionPts,refinementRegionNames, refinementRegionLocs, + bounds, userBounds, xGrid, yGrid, xMesh, yMesh, + true, false) + + addObserver(proj,"CURVE_DID_CHANGE_NOTIFICATION",curveDidChange) + addObserver(proj,"MODEL_DID_CHANGE_NOTIFICATION",modelDidChange) + addObserver(proj,"BGRID_DID_CHANGE_NOTIFICATION",backgroundGridDidChange) + addObserver(proj,"MESH_WAS_GENERATED_NOTIFICATION",meshWasGenerated) + addObserver(proj,"MESH_WAS_DELETED_NOTIFICATION",meshWasDeleted) + addObserver(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",refinementWasAdded) + addObserver(proj,"REFINEMENT_WAS_CHANGED_NOTIFICATION",refinementDidChange) + enableNotifications() +# +# Set some default values +# + addRunParameters!(proj) + addSpringSmoother!(proj) + enableUndo() + return proj +end +""" +hasBackgroundGrid(proj::Project) + +Tests to see if the project has a backgroundGrid dictionary defined. +""" +function hasBackgroundGrid(proj::Project) + controlDict = getControlDict(proj) + if haskey(controlDict,"BACKGROUND_GRID") + return true + else + return false + end +end + +function assemblePlotArrays(proj::Project) + + empty!(proj.outerBndryPoints) + empty!(proj.outerBndryNames) + empty!(proj.innerBoundaryChainNames) + empty!(proj.innerBoundaryPoints) + empty!(proj.innerBoundaryNames) + empty!(proj.xGrid) + empty!(proj.yGrid) + + bounds = emptyBounds() + + modelDict = getModelDict(proj) + + if haskey(modelDict,"OUTER_BOUNDARY") + outerBoundary = modelDict["OUTER_BOUNDARY"] + obChain = outerBoundary["LIST"] + proj.outerBndryPoints = chainPoints(obChain,defaultPlotPts) + + chB = chainBounds(proj.outerBndryPoints) + bounds = bboxUnion(bounds,chB) + + for crv in obChain + push!(proj.outerBndryNames,crv["name"]) + end + end + + if haskey(modelDict,"INNER_BOUNDARIES") + innerBoundaries = modelDict["INNER_BOUNDARIES"] + innerBoundaryList = innerBoundaries["LIST"] #LIST of CHAINS + for d in innerBoundaryList + push!(proj.innerBoundaryChainNames, d["name"]) + ibChain = d["LIST"] + ibPnts = chainPoints(ibChain,defaultPlotPts) + push!(proj.innerBoundaryPoints,ibPnts) + chB = chainBounds(ibPnts) + bounds = bboxUnion(bounds,chB) + names = String[] + for crv in ibChain + push!(names,crv["name"]) + end + push!(proj.innerBoundaryNames,names) + end + end + + controlDict = getControlDict(proj) + + if haskey(controlDict,"REFINEMENT_REGIONS") + refinementBlock = controlDict["REFINEMENT_REGIONS"] + refinementsList = refinementBlock["LIST"] + for ref in refinementsList + addRefinementRegionPoints!(proj,ref) + end + end + proj.bounds = bounds +end + +function projectBounds(proj::Project) + bounds = emptyBounds() + + if !isempty(proj.outerBndryPoints) + chB = chainBounds(proj.outerBndryPoints) + bounds = bboxUnion(bounds,chB) + end + + if !isempty(proj.innerBoundaryPoints) + for i = 1:length(proj.innerBoundaryPoints) + ibPnts = proj.innerBoundaryPoints[i] + chB = chainBounds(ibPnts) + bounds = bboxUnion(bounds,chB) + end + end + return bounds +end + +function projectGrid(proj::Project) + + controlDict = proj.projectDictionary["CONTROL_INPUT"] + + if haskey(controlDict,"BACKGROUND_GRID") + bgDict = controlDict["BACKGROUND_GRID"] + + if haskey(bgDict,"dx") + N = intArrayForKeyFromDictionary("N", bgDict) + x0 = realArrayForKeyFromDictionary("x0",bgDict) + left = x0[1] + bottom = x0[2] + xGrid = zeros(Float64, N[1]+1) + yGrid = zeros(Float64, N[2]+1) + dx = realArrayForKeyFromDictionary("dx", bgDict) + for i = 1:N[1]+1 + xGrid[i] = left + (i-1)*dx[1] + end + for j = 1:N[2]+1 + yGrid[j] = bottom + (j-1)*dx[2] + end + else + dx = realArrayForKeyFromDictionary("background grid size", bgDict) + bounds = proj.bounds + + width = bounds[RIGHT] - bounds[LEFT] + height = bounds[TOP] - bounds[BOTTOM] + + Nx = Int(round(width/dx[1])) + 3 # Want the model inside the grid + Ny = Int(round(height/dx[2])) + 3 + + xGrid = zeros(Float64, Nx) + yGrid = zeros(Float64, Ny) + + for i = 1:Nx + xGrid[i] = bounds[LEFT] + (i-2)*dx[1] # Arrays start at 1, ugh. + end + for j = 1:Ny + yGrid[j] = bounds[BOTTOM] + (j-2)*dx[2] + end + end + end + + return xGrid, yGrid +end +# +# NOTIFICATION ACTIONS +# +function curveDidChange(proj::Project,crv::Dict{String,Any}) + curveName = getCurveName(crv) +# +# Find the curve location: See if the curve is in the outer boundary +# + for (i,s) in enumerate(proj.outerBndryNames) + if s == curveName + proj.outerBndryPoints[i] = curvePoints(crv,defaultPlotPts) + if !isnothing(proj.plt) + options = proj.plotOptions + updatePlot!(proj, options) + end + return nothing + end + end +# +# Otherwise, see if it is an inner boundary +# + crvNumber, bndryNumber = innerBoundaryIndices(proj,curveName) + if crvNumber == 0 || bndryNumber == 0 + return nothing + end + innerBoundaryPoints = proj.innerBoundaryPoints[bndryNumber] + innerBoundaryPoints[crvNumber] = curvePoints(crv,defaultPlotPts) + proj.backgroundGridShouldUpdate = true + + if !isnothing(proj.plt) + options = proj.plotOptions + updatePlot!(proj, options) + end + return nothing +end + +function modelDidChange(proj::Project, sender::Project) + + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (options & MODEL) == 0 + options = options + MODEL + end + updatePlot!(proj, options) + end +end + +function backgroundGridDidChange(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + proj.backgroundGridShouldUpdate = true + options = proj.plotOptions + if (options & GRID) == 0 + options = options + GRID + end + updatePlot!(proj, options) + end +end + +function refinementWasAdded(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (options & REFINEMENTS) == 0 + options = options + REFINEMENTS + end + updatePlot!(proj, options) + end +end + +function refinementDidChange(proj::Project, sender::Dict{String,Any}) + regionName = sender["name"] + lst = getAllRefinementRegions(proj) + indx = 0 + for (i,r) in enumerate(lst) + if r["name"] == regionName + indx = i + break + end + end + + if indx > 0 + x = refinementRegionPoints(sender) + proj.refinementRegionPoints[indx] = x + proj.refinementRegionNames[indx] = sender["name"] + center = refinementRegionCenter(sender) + proj.refinementRegionLoc[indx] = center + + if !isnothing(proj.plt) + options = proj.plotOptions + if (options & REFINEMENTS) == 0 + options = options + REFINEMENTS + end + updatePlot!(proj, options) + end + else + println("Refinement region with name $regionName not found.") + end +end + +function meshWasGenerated(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + options = (MODEL & options) + MESH + proj.meshShouldUpdate = true + updatePlot!(proj, options) + end +end + +function meshWasDeleted(proj::Project, sender::Project) + if proj === sender && !isnothing(proj.plt) + options = proj.plotOptions + if (MESH & options) > 0 + options = options - MESH + end + proj.meshShouldUpdate = false + updatePlot!(proj, options) + end +end diff --git a/HQMTool/Source/Project/RefinementRegionsAPI.jl b/HQMTool/Source/Project/RefinementRegionsAPI.jl new file mode 100644 index 00000000..1c439034 --- /dev/null +++ b/HQMTool/Source/Project/RefinementRegionsAPI.jl @@ -0,0 +1,476 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" +newRefinementCenter(type, + center, meshSize, + width ) + +Create refinement center of `type` "smooth" or "sharp" centered at `center = [x,y,z]`` +with a mesh size `meshSize` spread over a radius `width`. +""" +function newRefinementCenter(name::String, type::String, + x0::Array{Float64}, h::Float64, + w::Float64 ) + disableUndo() + disableNotifications() + centerDict = Dict{String,Any}() + centerDict["TYPE"] = "REFINEMENT_CENTER" + setRefinementType!(centerDict,type) + setRefinementLocation!(centerDict,x0) + setRefinementGridSize!(centerDict,h) + setRefinementWidth!(centerDict,w) + setRefinementName!(centerDict,name) + enableNotifications() + enableUndo() + return centerDict +end +""" + addRefinementRegion!(proj::Project,r::Dict{String,Any}) + +Add the refinement region to the project +""" +function addRefinementRegion!(proj::Project,r::Dict{String,Any}) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + push!(lst,r) + addRefinementRegionPoints!(proj,r) + enableUndo() + registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Add Refinement Region") + enableNotifications() + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +""" + addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) + +Compute and add to the project the plotting points for the refinement region +""" +function addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) + + x = refinementRegionPoints(r) + push!(proj.refinementRegionPoints,x) + push!(proj.refinementRegionNames, r["name"]) + center = refinementRegionCenter(r) + push!(proj.refinementRegionLoc,center) +end +""" + refinementRegionPoints(r::Dict{String,Any}) + + Returns Array{Float64,2} being the plotting points of a refinement region +""" +function refinementRegionPoints(r::Dict{String,Any}) + + if r["TYPE"] == "REFINEMENT_CENTER" + center = getRefinementLocation(r) + radius = getRefinementWidth(r) + + N = defaultPlotPts + x = zeros(Float64,N+1,2) + t = zeros(Float64,N+1) + for i = 1:N+1 + t[i] = (i-1)/N + end + arcCurvePoints(center,radius,0.0,360.0,"degrees",t,x) + return x + else + xStart = realArrayForKeyFromDictionary("x0",r) + xEnd = realArrayForKeyFromDictionary("x1",r) + dx = xEnd - xStart + l = sqrt(dx[1]^2 + dx[2]^2) + w = realForKeyFromDictionary("w",r) + v = [-dx[2]/l,dx[1]/l] + x1 = xStart[1:2] + w*v + x2 = xEnd[1:2] + w*v + v = [dx[2]/l,-dx[1]/l] + x3 = xEnd[1:2] + w*v + x4 = xStart[1:2] + w*v + x = zeros(Float64,5,2) + x[1,:] = x1 + x[2,:] = x2 + x[3,:] = x3 + x[4,:] = x4 + x[5,:] = x1 + return x + end + +end +""" + refinementRegionCenter(r::Dict{String,Any}) + +Get, or compute, the center of the given refinement region. +""" +function refinementRegionCenter(r::Dict{String,Any}) + if r["TYPE"] == "REFINEMENT_CENTER" + center = getRefinementLocation(r) + return center[1:2] + else + xStart = realArrayForKeyFromDictionary("x0",r) + xEnd = realArrayForKeyFromDictionary("x1",r) + xAvg = 0.5*(xStart + xEnd) + return xAvg[1:2] + end +end +""" + removeRefinementRegion!(proj::Project, name::String) + +Delete the named refinement region. +""" +function removeRefinementRegion!(proj::Project, name::String) + i,r = getRefinementRegion(proj,name) + lst = getAllRefinementRegions(proj) + deleteat!(lst,i) + deleteat!(proj.refinementRegionLoc,i) + deleteat!(proj.refinementRegionNames,i) + deleteat!(proj.refinementRegionPoints,i) + registerWithUndoManager(proj,insertRefinementRegion!, (r,i,), "Remove Refinement Region") + enableNotifications() + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +""" + insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) + +Used by undo() +""" +function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) + lst = getAllRefinementRegions(proj) + registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Set Insert Refinement Region") + insert!(lst,indx,r) + x = refinementRegionPoints(r) + insert!(proj.refinementRegionPoints,indx,x) + center = refinementRegionCenter(r) + insert!(proj.refinementRegionLoc,indx,center) + insert!(proj.refinementRegionNames,indx,r["name"]) + postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + newRefinementLine(type, + start, end, + meshSize, + width ) + +Create refinement line of type "smooth" or "sharp" between `start` = [x,y,z] and `end` = [x,y,z] +with a mesh size `meshSize` spread over a width `width`. +""" +function newRefinementLine(name::String, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64 ) + disableUndo() + disableNotifications() + lineDict = Dict{String,Any}() + lineDict["TYPE"] = "REFINEMENT_LINE" + setRefinementType(lineDict,type) + setRefinementStart(lineDict,x0) + setRefinementEnd(lineDict,x1) + setRefinementGridSize(lineDict,h) + setRefinementWidth(lineDict,w) + setRefinementName!(lineDict,name) + enableNotifications() + enableUndo() + return lineDict +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementRegion(proj::Project, indx) + +Get the refinement region with index, indx from the project. Returns nothing if +there is none. The return value is a dictionary that represents the refinement region. +""" +function getRefinementRegion(proj::Project, indx::Int) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + if indx > length(lst) + printf("Index %i is larger than the number of refinement regions, %i", indx, length(lst)) + return nothing + end + return lst[indx] +end +# +# -------------------------------------------------------------------------------------- +# +""" + allRefinementRegions(proj::Project) + +Get the list of refinement regions. +""" +function getAllRefinementRegions(proj::Project) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + return lst +end +# +# -------------------------------------------------------------------------------------- +# +""" + (i,r) = getRefinementRegion(project, name) + +Get the refinement region with the given name and its location in the list of refinement regions. +""" +function getRefinementRegion(proj::Project, name::String) + lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") + for (i,r) in enumerate(lst) + if r["name"] == name + return i,r + end + end + println("Refinement region with name %s not found",name) + return nothing +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementType!(refinementRegion, type) + +Set the type, either "smooth" or "sharp" for the given refinement region. +""" +function setRefinementType!(r::Dict{String,Any}, type::String) + if !in(type,refinementTypes) + println("Acceptable refinement types are `smooth` and `sharp`. Try again.") + return + end + + if haskey(r,"type") + oldType = r["type"] + registerWithUndoManager(r,setRefinementType!, (oldType,), "Set Refinement Type") + end + r["type"] = type +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementType(r::Dict{String,Any}) + +Return the type of refinement, either "smooth" or "sharp". `r` is the dictionary that +represents the refinement region. +""" +function getRefinementType(r::Dict{String,Any}) + return r["type"] +end +""" + setRefinementName!(r::Dict{String,Any}, type) + +Set a name for the refinement region.`r` is the dictionary that + represents the refinement region. +""" +function setRefinementName!(r::Dict{String,Any}, name::String) + if haskey(r,"name") + oldName = r["name"] + registerWithUndoManager(r,setRefinementName!, (oldName,), "Set Refinement Name") + end + r["name"] = name + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementName(r::Dict{String,Any}) + +Return name of the refinement. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementName(r::Dict{String,Any}) + return r["name"] +end# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementLocation!(refinementCenter, location) + +Set the location of a refinement center to location = [x,y,z]. +""" +function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) + return nothing +end + +function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") + end + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementLocation(r::Dict{String,Any}) + +Return Array{Float64} of the location of the refinement center.`r` is the dictionary that +represents the refinement region. +""" +function getRefinementLocation(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x0",r) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementGridSize(r::Dict{String,Any}, h) + +Set the grid size, `h` for the refinement region. `r` is the dictionary that +represents the refinement region. +""" +function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) + if haskey(r,"h") + old = r["h"] + registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") + end + r["h"] = string(h) +end +function setRefinementGridSize!(r::Dict{String,Any}, h::String) + hf = parse(Float64,h) + setRefinementGridSize!(r,hf) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementGridSize(r::Dict{String,Any}) + +Returns the grid size,h, as Float64. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementGridSize(r::Dict{String,Any}) + return parse(Float64,r["h"]) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementWidth!(r::Dict{String,Any}, width) + +Set the width of the refinement region. `r` is the dictionary that +represents the refinement region. +""" +function setRefinementWidth!(r::Dict{String,Any},w::Float64) + if haskey(r,"w") + old = r["w"] + registerWithUndoManager(r,setRefinementWidth!, (old,), "Set Refinement Width") + end + r["w"] = string(w) + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +function setRefinementWidth!(r::Dict{String,Any},w::String) + wf = parse(Float64,w) + setRefinementWidth!(r,wf) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementWidth(r::Dict{String,Any}) + +Returns the region width,w, as Float64. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementWidth(r::Dict{String,Any}) + return parse(Float64,r["w"]) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementStart!(refinementRegion, location) + +Set the start point location of a refinement line, `location = [x, y, z]`. +""" +function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(r,)) +end +function setRefinementStart!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x0") + old = r["x0"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") + end + r["x0"] = x0Str +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementStart (r::Dict{String,Any}) + +Return Array{Float64} of the start location of the refinement line. `r` is the dictionary that +represents the refinement region. +""" +function getRefinementStart(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x0",r) +end +# +# -------------------------------------------------------------------------------------- +# +""" + setRefinementEnd(refinementRegion, location) + +Set the end point location of a refinement line, `location = [x, y, z]`. +""" +function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + if haskey(r,"x1") + old = r["x1"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") + end + x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + r["x1"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) + if haskey(r,"x1") + old = r["x1"] + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") + end + r["x1"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) +end +# +# -------------------------------------------------------------------------------------- +# +""" + getRefinementEnd(r::Dict{String,Any}) + +Return Array{Float64} of the end location of the refinement line +""" +function getRefinementEnd(r::Dict{String,Any}) + return realArrayForKeyFromDictionary("x1",r) +end diff --git a/HQMTool/Source/Project/RunParametersAPI.jl b/HQMTool/Source/Project/RunParametersAPI.jl new file mode 100644 index 00000000..cd51b452 --- /dev/null +++ b/HQMTool/Source/Project/RunParametersAPI.jl @@ -0,0 +1,190 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) + +Add a RUN_PARAMETERS block and set all the parameters in one call. +""" +function addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) + + setFileNames!(proj) + setPlotFileFormat!(proj,plotFormat) + setMeshFileFormat!(proj,meshFileFormat) + setPolynomialOrder!(proj,polynomialOrder) + + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + registerWithUndoManager(proj,removeRunParameters!, (nothing,), "Add Run Parameters") + + return rpDict +end +""" + removeRunParameters!(proj::Project) + +Remove the run parameters block from the project. +""" +function removeRunParameters!(proj::Project) + cDict = getControlDict(proj) + if haskey(cDict,"RUN_PARAMETERS") + delete!(cDict,"RUN_PARAMETERS") + end +end + +""" + setName(proj::Project,name::String) + +The `name` of the project is the filename to be used by the mesh, plot, and +stats files. It is also the name of the control file the tool will produce. +""" +function setName!(proj::Project,name::String) + + oldName = proj.name + registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") + proj.name = name + setFileNames!(proj) +end +""" + getName(proj::Project) + +Returns the filename to be used by the mesh, plot, control, and +stats files. +""" +function getName(proj::Project) + return proj.name +end +""" +setFolder(proj::Project,folder::String) + +Set the path to the directory where the mesh, plot, control, and stats files +will be written +""" +function setFolder(proj::Project,folder::String) + oldPath = proj.path + registerWithUndoManager(proj,setFolder,(oldPath,),"Set Project Folder") + proj.path = folder +end +""" + path(proj::Project) + +Returns the directory where the project files will be written +""" +function getfolder(proj::Project) + return proj.path +end +""" + setPolynomialOrder(proj::Project, p::Int) + +Set the polynomial order for boundary curves in the mesh file to `p`. +""" +function setPolynomialOrder!(proj::Project, p::Int) + key = "polynomial order" + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + if haskey(rpDict,key) + oldP = parse(Int,rpDict[key]) + registerWithUndoManager(proj,setPolynomialOrder!,(oldP,),"Set Order") + end + rpDict["polynomial order"] = string(p) +end +""" + getPolynomialOrder(proj::Project) + +Returns the polynomial order for boundary curves in the mesh file. +""" +function getPolynomialOrder(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["polynomial order"] +end +""" + setMeshFileFormat(proj::Project, meshFileFormat::String) + +Set the file format for the mesh file. Acceptable choices +are "ISM" and "ISM-V2". +""" +function setMeshFileFormat!(proj::Project, meshFileFormat::String) + if !in(meshFileFormat,meshFileFormats) + println("Acceptable file formats are ISM and ISM-V2. Try again.") + return + end + key = "mesh file format" + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + if haskey(rpDict,key) + oldFormat = rpDict[key] + registerWithUndoManager(proj,setMeshFileFormat!,(oldFormat,),"Set Mesh Format") + end + rpDict[key] = meshFileFormat +end +""" + getMeshFileFormat(proj::Project) + +Returns the format in which the mesh will be written. +""" +function getMeshFileFormat(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["mesh file format"] +end +""" + setPlotFileFormat(proj::Project, plotFileFormat::String) + +Set the file format for the plot file. Acceptable choices +are "sem", which includes interior nodes and boundary nodes and "skeleton", which includes +only the corner nodes. +""" +function setPlotFileFormat!(proj::Project, plotFileFormat::String) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + key = "plot file format" + if haskey(rpDict,key) + oldFormat = rpDict[key] + registerWithUndoManager(proj,setPlotFileFormat!,(oldFormat,),"Set Plot Format") + end + rpDict[key] = plotFileFormat +end +""" + getPlotFileFormat(proj::Project) + +Returns the plot file format. +""" +function getPlotFileFormat(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["plot file format"] +end + +function setFileNames!(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") + rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") + rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") + end + + function getMeshFileName(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["mesh file name"] + end diff --git a/HQMTool/Source/Project/SmootherAPI.jl b/HQMTool/Source/Project/SmootherAPI.jl new file mode 100644 index 00000000..eb046084 --- /dev/null +++ b/HQMTool/Source/Project/SmootherAPI.jl @@ -0,0 +1,118 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +""" + addSpringSmoother!(status::String, type::String, nIterations::Int) + + status is either `ON` or `OFF` + type is either `LinearSpring` or `LinearAndCrossbarSpring` + +""" +function addSpringSmoother!(proj::Project,status::String = "ON", + type::String = "LinearAndCrossbarSpring", + nIterations::Int = 25) + if !in(status,statusValues) + println("Acceptable smoother status are `ON` and `OFF`. Try again.") + return + end + if !in(type,smootherTypes) + println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + return + end + setSmoothingStatus!(proj,status) + setSmoothingType!(proj,type) + setSmoothingIterations!(proj,nIterations) +end +""" + setSmoothingStatus(proj:Project, status::String) + +status is either "ON" or "OFF" +""" +function setSmoothingStatus!(proj::Project, status::String) + if !in(status,statusValues) + println("Acceptable smoother status are `ON` and `OFF`. Try again.") + return + end + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["smoothing"] = status +end +""" + smoothingStatus(proj::Project) + +Returns whether the smoother will be "ON" or "OFF" +""" +function getSmoothingStatus(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["smoothing"] +end +""" +setSmoothingType!(proj:Project, status::String) + +type is either `LinearSpring` or `LinearAndCrossbarSpring` +""" +function setSmoothingType!(proj::Project, type::String) + if !in(type,smootherTypes) + println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + return + end + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["smoothing type"] = type +end +""" + smoothingType(proj::Project) + +Returns either "LinearSpring" or "LinearAndCrossbarSpring" +""" +function getSmoothingType(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["smoothing type"] +end +""" + setSmoothingIterations!((proj::Project, iterations::Int) + +Set the number of iterations to smooth the mesh. +""" +function setSmoothingIterations!(proj::Project, iterations::Int) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + smDict["number of iterations"] = iterations +end +""" + +""" +function getSmoothingIterations(proj::Project) + smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") + return smDict["number of iterations"] + +end +""" + removeSpringSmoother!(proj::Project) + +Remove the background grid block from the project. +""" +function removeSpringSmoother!(proj::Project) + cDict = getControlDict(proj) + delete!(cDict,"SPRING_SMOOTHER") +end diff --git a/HQMTool/Source/Project/Undo.jl b/HQMTool/Source/Project/Undo.jl new file mode 100644 index 00000000..c14438f3 --- /dev/null +++ b/HQMTool/Source/Project/Undo.jl @@ -0,0 +1,142 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +struct UROperation + object::Any + action::Any + data ::Tuple + name ::String +end + +@enum UNDO_OPERATION_TYPE begin + UNDO_USER_OPERATION = 0 + UNDO_OPERATION = 1 + REDO_OPERATION = 2 + UNDO_IGNORE = 3 +end + +#= +TODO: The undo framework currently works globally, within the REPL. It *should* work project-by-project. +To make it project based, undo() would be replaced by undo(project) and an .undoStack +property of the project would replace HQMglobalUndoStack. This is +not a big deal except if multiple projects are open, and muliple objects like curves have been +defined but not added to a project. In interactive mode curves are separate from projects until +added. (The same curve could be added to multiple projects.) So some logic needs to be +figured out before modifying below. If only one project is managed per session, +then this is not a problem. +=# +HQMglobalUndoStack = [] +HQMglobalRedoStack = [] +HQMglobalChangeOP = UNDO_IGNORE + +function undo() + if !isempty(HQMglobalUndoStack) + op = pop!(HQMglobalUndoStack) + f = op.action + d = op.data + obj = op.object + global HQMglobalChangeOP = UNDO_OPERATION + if isnothing(d[1]) + f(obj) + else + f(obj,d...) + end + global HQMglobalChangeOP = UNDO_USER_OPERATION + return "Undo "*op.name + end + return "Empty undo stack. No action performed." +end + +function redo() + if !isempty(HQMglobalRedoStack) + op = pop!(HQMglobalRedoStack) + f = op.action + d = op.data + obj = op.object + global HQMglobalChangeOP = REDO_OPERATION + if isnothing(d[1]) + f(obj) + else + f(obj,d...) + end + global HQMglobalChangeOP = UNDO_USER_OPERATION + return "Redo " * op.name + end + return "Empty redo stack. No action performed." +end + +function registerUndo(obj, action, data::Tuple, name::String) + uOp = UROperation(obj,action,data,name) + push!(HQMglobalUndoStack,uOp) +end + +function registerWithUndoManager(obj, action, oldData::Tuple, name::String) + + if HQMglobalChangeOP == UNDO_USER_OPERATION #User action + registerUndo(obj,action,oldData,name) + elseif HQMglobalChangeOP == UNDO_OPERATION #Undo operation + registerRedo(obj,action,oldData,name) + elseif HQMglobalChangeOP == REDO_OPERATION #Redo operation + registerUndo(obj,action,oldData,name) + else + # UNDO_IGNORE + end +end + +function registerRedo(obj, action, data::Tuple, name::String) + rOp = UROperation(obj,action,data,name) + push!(HQMglobalRedoStack,rOp) +end + +function clearUndoRedo() + empty!(HQMglobalUndoStack) + empty!(HQMglobalRedoStack) +end + +function undoActionName() + if !isempty(HQMglobalUndoStack) + op = last(HQMglobalUndoStack) + return op.name + end + return "No undo action in queue" +end + + +function redoActionName() + if !isempty(HQMglobalRedoStack) + op = last(HQMglobalRedoStack) + return op.name + end + return "No redo action in queue" +end + +function disableUndo() + global HQMglobalChangeOP = UNDO_IGNORE +end + +function enableUndo() + global HQMglobalChangeOP = UNDO_USER_OPERATION +end diff --git a/HQMTool/Source/Viz/VizMesh.jl b/HQMTool/Source/Viz/VizMesh.jl new file mode 100644 index 00000000..452e9f2c --- /dev/null +++ b/HQMTool/Source/Viz/VizMesh.jl @@ -0,0 +1,78 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +function getMeshFromMeshFile(meshFile::AbstractString) + + open(meshFile,"r") do f + line = strip(readline(f)) #Header Should be ISM-V2 + if line != "ISM-V2" + error("Mesh file must be ISM-V2") + return nothing + end + line = readline(f) # Numbers of nodes, edges ... + values = split(line) + + nNodes = parse(Int,values[1]) + nEdges = parse(Int,values[2]) +# +# Read the nodes +# + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64,values[j]) + end + end +# +# Read the edges and construct the lines array +# + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) + + for i = 1:3:3*nEdges + + values = split(readline(f)) + n = parse(Int,values[1]) + m = parse(Int,values[2]) + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN + + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + + end + return xMesh, yMesh + end + +end + +function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) + lines!(plt[1,1], xMesh,yMesh) +end diff --git a/HQMTool/Source/Viz/VizProject.jl b/HQMTool/Source/Viz/VizProject.jl new file mode 100644 index 00000000..8104037e --- /dev/null +++ b/HQMTool/Source/Viz/VizProject.jl @@ -0,0 +1,194 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +using GLMakie + +const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 +const REFINEMENTS = 8; const ALL = 15 +""" + plotProject!(proj::Project, plotOptions::Int = 0) + +Plot objects specified by the `plotOptions`. Construct the `plotOptions` by the sum +of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. + +Example: To plot the model and the grid, `plotOptions = MODEL + GRID`. To plot +just the mesh, `plotOptions = MESH`. + +To plot everything, `plotOptions = MODEL + GRID + MESH + REFINEMENTS` + +Contents are overlayed in the order: GRID, MESH, MODEL, REFINEMENTS +""" +function plotProject!(proj::Project, plotOptions::Int = 0) + + if isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + end + plt = proj.plt + ax = plt[1,1] = Axis(plt) + + plotTheModel = ((plotOptions & MODEL) != 0) + plotTheGrid = ((plotOptions & GRID) != 0) + plotTheMesh = ((plotOptions & MESH) != 0) + plotTheRefinements = ((plotOptions & REFINEMENTS) != 0) + proj.plotOptions = plotOptions +# +# Plot the grid +# + if plotTheGrid && hasBackgroundGrid(proj) + if proj.backgroundGridShouldUpdate # Lazy evaluation of the background grid + proj.bounds = projectBounds(proj) + proj.xGrid, proj.yGrid = projectGrid(proj) + proj.backgroundGridShouldUpdate = false + end + nX = length(proj.xGrid) + nY = length(proj.yGrid) + z = zeros(Float64,nX,nY) + wireframe!(plt[1,1],proj.xGrid,proj.yGrid,z) + end +# +# Plot the mesh +# + if plotTheMesh + # Lazy creation of mesh plotting arrays + if proj.meshShouldUpdate || (isempty(proj.xMesh) && isempty(proj.yMesh)) + meshFileName = getMeshFileName(proj) + if isfile(meshFileName) + proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName) + plotMesh(plt, proj.xMesh, proj.yMesh) + end + proj.meshShouldUpdate = false + else + plotMesh(plt, proj.xMesh, proj.yMesh) + end + end +# +# Plot the model +# + if plotTheModel +# +# Plot the outer innerBoundaries +# + if !isempty(proj.outerBndryNames) + plotNames = ["Outer."*s for s in proj.outerBndryNames] + plotChain!(plt,proj.outerBndryPoints, plotNames) + end +# +# Plot the inner innerBoundaries +# + if !isempty(proj.innerBoundaryChainNames) + for i = 1:length(proj.innerBoundaryChainNames) + innerBndryPts = proj.innerBoundaryPoints[i] + innerBndryNames = [ proj.innerBoundaryChainNames[i]*"."*s for s in proj.innerBoundaryNames[i]] + plotChain!(plt,innerBndryPts, innerBndryNames) + end + end + if !isempty(proj.outerBndryNames) || !isempty(proj.innerBoundaryChainNames) + plt[1,2] = Legend(plt, ax, "Curves", framevisible = false, labelsize = 24, titlesize = 28) + end + + end +# +# Plot refinement regions +# + if plotTheRefinements + if !isempty(proj.refinementRegionNames) + plotRefinement(plt,proj.refinementRegionPoints, + proj.refinementRegionNames, + proj.refinementRegionLoc) + end + end +# +# Display the plot +# + ax.aspect = DataAspect() + display(plt) +end +""" + updatePlot!(proj::Project) + +This version replots the figure with the current options. Legacy. +""" +function updatePlot!(proj::Project) + if !isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + plotOptions = proj.plotOptions + plotProject!(proj, plotOptions) + end +end +""" +updatePlot!(proj::Project, plotOptions::Int) + +Replot with the new plotOptions = combinations (sums) of + + GRID, MESH, MODEL, REFINEMENTS + +Example: updatePlot(p, MESH + MODEL) +""" +function updatePlot!(proj::Project, plotOptions::Int) + if !isnothing(proj.plt) + proj.plt = Figure(resolution = (1500, 1500)) + plotProject!(proj, plotOptions) + end +end + +function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) + x = chainPoints[1] + plotCurve(plt, x, labels[1]) + + s = length(labels) + + for i = 2:s + x = chainPoints[i] + plotCurve(plt,x,labels[i]) + end +end + +function plotCurve(plt, points::Matrix{Float64}, label::String) + lines!(plt[1,1],points[:,1],points[:,2], label = label, linewidth = 5 ) + s = size(points) + np = div(s[1], 2, RoundNearest) + if s[1] == 3 + np = 2 + end + dx = points[np+1,1] - points[np-1,1] + dy = points[np+1,2] - points[np-1,2] + theta = atan(dy,dx) + if(abs(dy) <= 0.0001) #Not pretty + theta = 0.0 + end + pp = (points[np,1],points[np,2]) + text!(plt[1,1],label,position = pp, align = (:center,:center), rotation = theta ) +end + +function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String}, loc::Array{Array{Float64}}) + + for (i,reg) in enumerate(points) + lines!(plt[1,1],reg[:,1],reg[:,2], label = label[i], linewidth = 5, linestyle = :dot, color=:black ) + p = loc[i] + pp = (p[1],p[2]) + text!(plt[1,1],label[i],position = pp, align = (:center,:center)) + end +end diff --git a/examples/AllFeatures.control b/examples/AllFeatures.control index 880bb474..8244db77 100644 --- a/examples/AllFeatures.control +++ b/examples/AllFeatures.control @@ -101,9 +101,9 @@ background grid size = [3.0,3.0,0.0] \end{BACKGROUND_GRID} \begin{RUN_PARAMETERS} - mesh file name = Demo/AllFeatures.mesh + mesh file name = examples/AllFeatures.mesh plot file format = skeleton - plot file name = Demo/AllFeatures.tec + plot file name = examples/AllFeatures.tec stats file name = none mesh file format = ISM-V2 polynomial order = 4 From 16be727938bd626379e2988d9d103e9ded9179f4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 11 Mar 2022 14:33:22 +0100 Subject: [PATCH 004/164] add capability to set ABAQUS for the meshFileFormat --- HQMTool/Doc/HQMTool.md | 134 ++++++++++----------- HQMTool/Source/Project/RunParametersAPI.jl | 64 +++++----- 2 files changed, 101 insertions(+), 97 deletions(-) diff --git a/HQMTool/Doc/HQMTool.md b/HQMTool/Doc/HQMTool.md index ed747d79..03793642 100644 --- a/HQMTool/Doc/HQMTool.md +++ b/HQMTool/Doc/HQMTool.md @@ -24,7 +24,7 @@ HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. ## Introduction -HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. +HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run runDemo() @@ -85,7 +85,7 @@ To develop the model, one adds curves to the outer boundary or to multiple inner - Lines defined by their end points - Circular arcs -In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. +In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. @@ -115,15 +115,15 @@ To create generate a mesh you - [Create a project](#newProject) p = newProject(,) - + - [Create inner and outer boundary curves](#DefiningCurves) - + c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) c = new(, xEqn, yEqn, zEqn ) (Parametric equation) c = new(, dataFile) (Spline) c = new(, nKnots, knotsMatrix) (also Spline) - + - [Add curves](#AddingCurves) to build the model to see what you have added, add!(p, ) (Add outer boundary curve) @@ -132,11 +132,11 @@ To create generate a mesh you - To [visualize](#Plotting) the project's model, plotProject(p,MODEL) - + To update the plot at any time, use - + updatePlot!(p, options) - + Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) - Set the [background grid](#(#BackgroundGrid)) @@ -144,17 +144,17 @@ To create generate a mesh you addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) *OR* addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) - + addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) - [Adjust parameters](#RunParameters), if desired (e.g.) setPolynomialOrder!(p,order) - + - Generate the mesh generateMesh(p) - + The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. @@ -164,11 +164,11 @@ The mesh will be stored in `` with the name `.mesh`. The co ### New Project (Return:Project) proj = newProject(name::String, folder::String) - + The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). - + ### Opening an existing project file - + (Return:Project) proj = openProject(fileName::String, folder::String) @@ -201,7 +201,7 @@ The project name is the name under which the mesh, plot, statistics and control setName!(proj::Project,name::String) - + ### Getting the current name of a Project [Return:String] getName(proj::Project) @@ -211,7 +211,7 @@ The project name is the name under which the mesh, plot, statistics and control ### Editing the Run Parameters The run parameters can be enquired and set with these getter/setter pairs: - + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) [Return:Int] getPolynomialOrder(proj::Project) [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) @@ -219,12 +219,12 @@ The run parameters can be enquired and set with these getter/setter pairs: [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) [Return:String] getPlotFileFormat(proj::Project) -The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** +The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** ### Changing the output file names By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with - + [Return:nothing] setName!(proj::Project,name::String) [Return:String] getName(proj::Project) [Return:nothing] setFolder!(proj::Project,folder::String) @@ -233,7 +233,7 @@ By default, the mesh, plot and stats files will be written with the name and pat ### Adding the background grid There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. - + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) @@ -242,10 +242,10 @@ Use one of the first two if there is no outer boundary. With the first, a rectan ### Smoothing Operations -A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. - +A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. + To change the defaults, the smoother parameters can be set/enquired with the functions - + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) [Return:String] getSmoothingStatus(proj::Project) [Return:nothing] setSmoothingType!(proj::Project, type::String) @@ -253,49 +253,49 @@ To change the defaults, the smoother parameters can be set/enquired with the fun [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) [Return:Int] getSmoothingIterations(proj::Project) -`status` is either "ON" or "OFF". +`status` is either "ON" or "OFF". To remove the smoother altogether, - + [Return:nothing] removeSpringSmoother!(proj::Project) ### Manual Refinement Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. - + To create a refinement center, - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, x0::Array{Float64}, h::Float64, w::Float64 ) - + where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. - + Similarly, one can create a `RefinementLine`, - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, x0::Array{Float64}, x1::Array{Float64}, h::Float64, w::Float64 ) where `x0` is the start postition and `x1` is the end of the line. - + To add a refinement region to the project, [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) - -To get the indx'th refinement region from the project, or to get - a refinement region with a given name, use + +To get the indx'th refinement region from the project, or to get + a refinement region with a given name, use [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) - -Finally, to get a list of all the refinement regions, - + +Finally, to get a list of all the refinement regions, + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) - + A refinement region can be edited by using the following - + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) [Return:String] getRefinementType(r::Dict{String,Any}) [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) @@ -304,16 +304,16 @@ A refinement region can be edited by using the following [Return:float64] getRefinementGridSize(r::Dict{String,Any}) [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) [Return:float64] getRefinementWidth(r::Dict{String,Any}) - + where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. - + To further edit a `RefinementLine`, use the methods - + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) - + # Boundary Curves ### Adding Outer and Inner Boundaries @@ -330,7 +330,7 @@ To further edit a `RefinementLine`, use the methods Example: add!(p,circ) - + - Adding an inner boundary curve [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @@ -366,29 +366,29 @@ Four curve types can be added to the outer and inner boundary curve chains. They ### Parametric Equations -- Creating new +- Creating new - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) Generic: new(...) - - Returns a new parametric equation. Equations must be of the form - + + Returns a new parametric equation. Equations must be of the form + () = ... - + The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. - + Example: - + x(s) = 2.0 + 3*cos(2*pi*s)^2 - + The z-Equation is optional, but for now must define zero for z. - + ### Line Defined by End Points - [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, xStart::Array{Float64}, xEnd::Array{Float64}) Generic: new(...) @@ -400,20 +400,20 @@ Example: cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) ### Circular Arc - [Return:Dict{String,Any}] newCircularArcCurve(name::String, - center::Array{Float64}, + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String) Generic: new(...) The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". - -Example: + +Example: iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - + ### Spline Curve A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. @@ -440,11 +440,11 @@ If the curve is to be closed. The last point must be the same as the first. ## Editing Curves -You can determine the type of a curve by +You can determine the type of a curve by [Return:String] getCurveType(crv::Dict{String,Any}) - -For any of the curves, their name can be changed by + +For any of the curves, their name can be changed by setCurveName!(crv::Dict{String,Any}, name::String) @@ -464,7 +464,7 @@ Otherwise there are special functions to change the parameters of curves [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) - + [Return:String] getXEqn(crv::Dict{String,Any}) [Return:String] getYEqn(crv::Dict{String,Any}) [Return:String] getZEqn(crv::Dict{String,Any}) @@ -484,7 +484,7 @@ In interactive mode, actions can be undone by the commands [Return:String] undo() [Return:String] redo() - + where the return string contains the name of the action performed. To find out what the next actions are, use diff --git a/HQMTool/Source/Project/RunParametersAPI.jl b/HQMTool/Source/Project/RunParametersAPI.jl index cd51b452..41f89f89 100644 --- a/HQMTool/Source/Project/RunParametersAPI.jl +++ b/HQMTool/Source/Project/RunParametersAPI.jl @@ -3,41 +3,41 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# """ - addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", + addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) Add a RUN_PARAMETERS block and set all the parameters in one call. """ -function addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", +function addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) - setFileNames!(proj) + setFileNames!(proj, meshFileFormat) setPlotFileFormat!(proj,plotFormat) setMeshFileFormat!(proj,meshFileFormat) setPolynomialOrder!(proj,polynomialOrder) @@ -62,7 +62,7 @@ end """ setName(proj::Project,name::String) -The `name` of the project is the filename to be used by the mesh, plot, and +The `name` of the project is the filename to be used by the mesh, plot, and stats files. It is also the name of the control file the tool will produce. """ function setName!(proj::Project,name::String) @@ -70,22 +70,22 @@ function setName!(proj::Project,name::String) oldName = proj.name registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") proj.name = name - setFileNames!(proj) + setFileNames!(proj, getMeshFileFormat(proj)) end """ getName(proj::Project) -Returns the filename to be used by the mesh, plot, control, and +Returns the filename to be used by the mesh, plot, control, and stats files. """ function getName(proj::Project) return proj.name -end +end """ setFolder(proj::Project,folder::String) Set the path to the directory where the mesh, plot, control, and stats files -will be written +will be written """ function setFolder(proj::Project,folder::String) oldPath = proj.path @@ -99,7 +99,7 @@ Returns the directory where the project files will be written """ function getfolder(proj::Project) return proj.path -end +end """ setPolynomialOrder(proj::Project, p::Int) @@ -127,11 +127,11 @@ end setMeshFileFormat(proj::Project, meshFileFormat::String) Set the file format for the mesh file. Acceptable choices -are "ISM" and "ISM-V2". +are "ISM", "ISM-V2" and "ABAQUS". """ function setMeshFileFormat!(proj::Project, meshFileFormat::String) if !in(meshFileFormat,meshFileFormats) - println("Acceptable file formats are ISM and ISM-V2. Try again.") + println("Acceptable file formats are ISM, ISM-V2, or ABAQUS. Try again.") return end key = "mesh file format" @@ -177,9 +177,13 @@ function getPlotFileFormat(proj::Project) return rpDict["plot file format"] end -function setFileNames!(proj::Project) +function setFileNames!(proj::Project, meshFileFormat::String) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") + if meshFileFormat == "ABAQUS" + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".inp") + else + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") + end rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") end From 8bbc47fe1c4aefb0c50af78a5151acd8a5371144 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 11 Mar 2022 20:44:36 +0100 Subject: [PATCH 005/164] add ability to plot mesh from ISM format version --- HQMTool/HQMTool.jl | 27 ++--- HQMTool/Source/Viz/VizMesh.jl | 181 +++++++++++++++++++++++-------- HQMTool/Source/Viz/VizProject.jl | 45 ++++---- 3 files changed, 170 insertions(+), 83 deletions(-) diff --git a/HQMTool/HQMTool.jl b/HQMTool/HQMTool.jl index 7d890306..2d346e1e 100644 --- a/HQMTool/HQMTool.jl +++ b/HQMTool/HQMTool.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -128,6 +128,7 @@ function iceCreamCone(folder::String) # To mesh, a background grid is needed # addBackgroundGrid!(p, [0.5,0.5,0.0]) + setMeshFileFormat!(p,"ISM") # # Show the model and grid # diff --git a/HQMTool/Source/Viz/VizMesh.jl b/HQMTool/Source/Viz/VizMesh.jl index 452e9f2c..7b08aa08 100644 --- a/HQMTool/Source/Viz/VizMesh.jl +++ b/HQMTool/Source/Viz/VizMesh.jl @@ -3,74 +3,159 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# -function getMeshFromMeshFile(meshFile::AbstractString) +function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) - open(meshFile,"r") do f - line = strip(readline(f)) #Header Should be ISM-V2 - if line != "ISM-V2" - error("Mesh file must be ISM-V2") - return nothing - end - line = readline(f) # Numbers of nodes, edges ... - values = split(line) + if meshFileFormat == "ISM-V2" + open(meshFile,"r") do f + line = strip(readline(f)) #Header Should be ISM-V2 + # if line != "ISM-V2" + # error("Mesh file must be ISM-V2") + # return nothing + # end + line = readline(f) # Numbers of nodes, edges ... + values = split(line) - nNodes = parse(Int,values[1]) - nEdges = parse(Int,values[2]) + nNodes = parse(Int,values[1]) + nEdges = parse(Int,values[2]) # -# Read the nodes +# Read the nodes # - nodes = zeros(Float64,nNodes,2) - for i = 1:nNodes - values = split(readline(f)) - for j = 1:2 - nodes[i,j] = parse(Float64,values[j]) - end - end + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64,values[j]) + end + end # -# Read the edges and construct the lines array +# Read the edges and construct the lines array # - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) - for i = 1:3:3*nEdges + for i = 1:3:3*nEdges - values = split(readline(f)) - n = parse(Int,values[1]) - m = parse(Int,values[2]) + values = split(readline(f)) + n = parse(Int,values[1]) + m = parse(Int,values[2]) - xMesh[i] = nodes[n,1] - xMesh[i+1] = nodes[m,1] - xMesh[i+2] = NaN + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN - yMesh[i] = nodes[n,2] - yMesh[i+1] = nodes[m,2] - yMesh[i+2] = NaN + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN - end - return xMesh, yMesh - end + end + return xMesh, yMesh + end + elseif meshFileFormat == "ISM" + open(meshFile,"r") do f + # there is no header to read so directly read in + line = readline(f) # Numbers of corners, elements and boundary polynomial order + values = split(line) + nNodes = parse(Int,values[1]) + nElements = parse(Int,values[2]) + nBndy = parse(Int, values[3]) +# +# Read the nodes +# + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64, values[j]) + end + end +# +# Read the element ids (and skip all the boundary information) +# + elements = zeros(Int64,nElements,4) + temp = zeros(Int64, 4) + for i = 1:nElements + values = split(readline(f)) + for j = 1:4 + elements[i,j] = parse(Int64, values[j]) + end + values = split(readline(f)) + for j = 1:4 + temp[j] = parse(Int64, values[j]) + end + if sum(temp) == 0 + # straight-sided edge so just skip the boundary labels + readline(f) + else + # curved edge so skip the boundary polynomial and the labels + for i = 1:nBndy+1 + readline(f) + end + readline(f) + end + end + # convenience mapping for element index corners + p = [[1 2 4 1] + [2 3 3 4]] + # Build the edges. This is only for plotting purposes so we might have some + # repeated edges but we don't care + edge_id = 0 + hash_table = Dict{Int, Int}() + edges = Dict{Int, Any}() + for j in 1:nElements + for k in 1:4 + id1 = elements[j , p[1,k]] + id2 = elements[j , p[2,k]] + key_val = id1 + id2 + edge_id += 1 + push!( hash_table , key_val => edge_id ) + push!( edges , edge_id => [id1 id2] ) + end # k + end # j + # set the total number of edges + nEdges = edge_id + # use the edge information and pull the corner node physical values + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) + edge_id = 0 + for i = 1:3:3*nEdges + edge_id += 1 + current_edge = edges[edge_id] + n = current_edge[1] + m = current_edge[2] + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN + + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + end + return xMesh, yMesh + end + end end function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) diff --git a/HQMTool/Source/Viz/VizProject.jl b/HQMTool/Source/Viz/VizProject.jl index 8104037e..18444d9a 100644 --- a/HQMTool/Source/Viz/VizProject.jl +++ b/HQMTool/Source/Viz/VizProject.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -32,10 +32,10 @@ const REFINEMENTS = 8; const ALL = 15 plotProject!(proj::Project, plotOptions::Int = 0) Plot objects specified by the `plotOptions`. Construct the `plotOptions` by the sum -of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. +of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. Example: To plot the model and the grid, `plotOptions = MODEL + GRID`. To plot -just the mesh, `plotOptions = MESH`. +just the mesh, `plotOptions = MESH`. To plot everything, `plotOptions = MODEL + GRID + MESH + REFINEMENTS` @@ -76,7 +76,8 @@ function plotProject!(proj::Project, plotOptions::Int = 0) if proj.meshShouldUpdate || (isempty(proj.xMesh) && isempty(proj.yMesh)) meshFileName = getMeshFileName(proj) if isfile(meshFileName) - proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName) + fileFormat = getMeshFileFormat(proj) + proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName, fileFormat) plotMesh(plt, proj.xMesh, proj.yMesh) end proj.meshShouldUpdate = false @@ -116,10 +117,10 @@ function plotProject!(proj::Project, plotOptions::Int = 0) if plotTheRefinements if !isempty(proj.refinementRegionNames) plotRefinement(plt,proj.refinementRegionPoints, - proj.refinementRegionNames, + proj.refinementRegionNames, proj.refinementRegionLoc) end - end + end # # Display the plot # @@ -141,7 +142,7 @@ end """ updatePlot!(proj::Project, plotOptions::Int) -Replot with the new plotOptions = combinations (sums) of +Replot with the new plotOptions = combinations (sums) of GRID, MESH, MODEL, REFINEMENTS @@ -163,7 +164,7 @@ function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) for i = 2:s x = chainPoints[i] plotCurve(plt,x,labels[i]) - end + end end function plotCurve(plt, points::Matrix{Float64}, label::String) @@ -171,7 +172,7 @@ function plotCurve(plt, points::Matrix{Float64}, label::String) s = size(points) np = div(s[1], 2, RoundNearest) if s[1] == 3 - np = 2 + np = 2 end dx = points[np+1,1] - points[np-1,1] dy = points[np+1,2] - points[np-1,2] @@ -190,5 +191,5 @@ function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String p = loc[i] pp = (p[1],p[2]) text!(plt[1,1],label[i],position = pp, align = (:center,:center)) - end + end end From 0d2543449c881fa10f7614e433dea0cef76041c1 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 12 Mar 2022 22:38:18 +0100 Subject: [PATCH 006/164] add capability to plot from the ABAQUS format as well --- HQMTool/HQMTool.jl | 15 ++++--- HQMTool/Source/Viz/VizMesh.jl | 82 ++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/HQMTool/HQMTool.jl b/HQMTool/HQMTool.jl index 2d346e1e..a9b2dd89 100644 --- a/HQMTool/HQMTool.jl +++ b/HQMTool/HQMTool.jl @@ -92,16 +92,15 @@ function iceCreamConeVerbose(folder::String) # # Show the model and grid # - plotProject!(p, MODEL+GRID) + plotProject!(p, MODEL+GRID) # # Generate the mesh and plot # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) -return p + return p end function iceCreamCone(folder::String) @@ -128,7 +127,9 @@ function iceCreamCone(folder::String) # To mesh, a background grid is needed # addBackgroundGrid!(p, [0.5,0.5,0.0]) - setMeshFileFormat!(p,"ISM") + setMeshFileFormat!(p, "ABAQUS") + meshFileFormat = getMeshFileFormat(p) + setFileNames!(p, meshFileFormat) # # Show the model and grid # diff --git a/HQMTool/Source/Viz/VizMesh.jl b/HQMTool/Source/Viz/VizMesh.jl index 7b08aa08..e2d07923 100644 --- a/HQMTool/Source/Viz/VizMesh.jl +++ b/HQMTool/Source/Viz/VizMesh.jl @@ -28,11 +28,7 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) if meshFileFormat == "ISM-V2" open(meshFile,"r") do f - line = strip(readline(f)) #Header Should be ISM-V2 - # if line != "ISM-V2" - # error("Mesh file must be ISM-V2") - # return nothing - # end + line = strip(readline(f)) # Header Should be ISM-V2 line = readline(f) # Numbers of nodes, edges ... values = split(line) @@ -155,6 +151,82 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) end return xMesh, yMesh end + elseif meshFileFormat == "ABAQUS" + # read in the entire file + file_lines = readlines(open(meshFile)) + # obtain the number of corners and elements in a circuitous way due to the ABAQUS format + # number of corner nodes + file_idx = findfirst(contains("*ELEMENT"), file_lines) - 1 + current_line = split(file_lines[file_idx], ",") + nNodes = parse(Int, current_line[1]) + # number of elements + file_idx = findfirst(contains("** ***** HOHQMesh boundary information ***** **"), file_lines) - 1 + current_line = split(file_lines[file_idx], ",") + nElements = parse(Int, current_line[1]) +# +# Read in the nodes +# + nodes = zeros(Float64,nNodes,2) + file_idx = 4 + for i in 1:nNodes + current_line = split(file_lines[file_idx], ",") + for j = 2:3 + nodes[i, j-1] = parse(Float64, current_line[j]) + end + file_idx += 1 + end # i +# +# Read the element ids (and skip all the boundary information) +# + elements = zeros(Int64,nElements,4) + # eat the element header + file_idx += 1 + for i = 1:nElements + current_line = split(file_lines[file_idx], ",") + for j = 2:5 + elements[i,j-1] = parse(Int64, current_line[j]) + end + file_idx += 1 + end + # convenience mapping for element index corners + p = [[1 2 4 1] + [2 3 3 4]] + # Build the edges. This is only for plotting purposes so we might have some + # repeated edges but we don't care + edge_id = 0 + hash_table = Dict{Int, Int}() + edges = Dict{Int, Any}() + for j in 1:nElements + for k in 1:4 + id1 = elements[j , p[1,k]] + id2 = elements[j , p[2,k]] + key_val = id1 + id2 + edge_id += 1 + push!( hash_table , key_val => edge_id ) + push!( edges , edge_id => [id1 id2] ) + end # k + end # j + # set the total number of edges + nEdges = edge_id + # use the edge information and pull the corner node physical values + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) + edge_id = 0 + for i = 1:3:3*nEdges + edge_id += 1 + current_edge = edges[edge_id] + n = current_edge[1] + m = current_edge[2] + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN + + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + end + return xMesh, yMesh end end From 3e0de6c4e3f528455028df94c69d783bc46a7579 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Sat, 19 Mar 2022 13:38:45 -0700 Subject: [PATCH 007/164] Add Curve tests Start adding unit tests. First Batch is for curves. Need to figure out how to organize tests into multiple files and then one to rule them all. --- src/Curves/CurveOperations.jl | 6 +- src/Project/CurvesAPI.jl | 20 +++--- src/Test/CurveTests.jl | 113 ++++++++++++++++++++++++++++++++++ src/Test/Tests.jl | 31 ++++++++++ src/Viz/VizProject.jl | 1 + 5 files changed, 158 insertions(+), 13 deletions(-) create mode 100644 src/Test/CurveTests.jl create mode 100644 src/Test/Tests.jl diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index a7de2eba..6fc8f060 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -93,8 +93,8 @@ function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) yArg = Symbol(yArgM.match) ey = Meta.parse(eqString) - point[1] = evalWithDict(ex,Dict(xArg=> t[i])) - point[2] = evalWithDict(ey,Dict(yArg=> t[i])) + point[1] = evalWithDict(ex,Dict(xArg=> t)) + point[2] = evalWithDict(ey,Dict(yArg=> t)) end @@ -134,7 +134,7 @@ function evalWithDict(ex::Expr, locals::Dict{Symbol}) end function curvePoints(crvDict::Dict{String,Any}, N::Int) - +# N = Number of intervals curveType::String = crvDict["TYPE"] if curveType == "PARAMETRIC_EQUATION_CURVE" diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 090e56d5..299ec15f 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -140,17 +140,17 @@ end Duplicate the given curve giving it the new name. """ -function duplicateCurve(crv::Dict{String,Any}, newName::String) - disableNotifications() - disableUndo() +# function duplicateCurve(crv::Dict{String,Any}, newName::String) +# disableNotifications() +# disableUndo() - duplicate = deepcopy(crv) - setCurveName!(duplicate,newName) +# duplicate = deepcopy(crv) +# setCurveName!(duplicate,newName) - enableNotifications() - enableUndo() - return duplicate -end +# enableNotifications() +# enableUndo() +# return duplicate +# end """ setCurveName!(curveDict, name) @@ -322,7 +322,7 @@ end Get the units for the start and end angles of a circular arc curve. """ -function getArcUnits!(arc::Dict{String,Any}) +function getArcUnits(arc::Dict{String,Any}) return arc["units"] end """ diff --git a/src/Test/CurveTests.jl b/src/Test/CurveTests.jl new file mode 100644 index 00000000..06c57ee4 --- /dev/null +++ b/src/Test/CurveTests.jl @@ -0,0 +1,113 @@ +using Test +include("../HQMTool.jl") + +@testset "Curve Tests" begin + @testset "ParametricCurve Tests" begin + xEqn = "x(t) = t" + yEqn = "y(t) = 2.0*t" + zEqn = "z(t) = 0.0" + name = "TestParametricCurve" + + crv = new(name, xEqn, yEqn, zEqn) + + @test typeof(crv) == Dict{String,Any} + @test getCurveType(crv) == "PARAMETRIC_EQUATION_CURVE" + @test getCurveName(crv) == name + @test getXEqn(crv) == xEqn + @test getYEqn(crv) == yEqn + @test getZEqn(crv) == zEqn + + # pt = zeros(Float64,2) + # peEquationCurvePoint(xEqn,yEqn,0.5,pt) + # pts = curvePoints(crv,2) + # @test isapprox(pts[1,:],[0.0,0.0]) + # @test isapprox(pts[2,:],[0.5,1.0]) + # @test isapprox(pts[3,:],[1.0,2.0]) + + end + + @testset "EndPointLine Tests" begin + xStart = [0.0,0.0,0.0] + xEnd = [1.0,1.0,0.0] + name = "EndPointLineCurve" + + crv = new(name,xStart,xEnd) + + @test typeof(crv) == Dict{String,Any} + @test getCurveType(crv) == "END_POINTS_LINE" + @test getCurveName(crv) == name + @test getStartPoint(crv) == xStart + @test getEndPoint(crv) == xEnd + + pt = curvePoint(crv, 0.5) + @test isapprox(pt,[0.5,0.5,0.0]) + + pts = curvePoints(crv,2) + @test isapprox(pts[1,:],[0.0,0.0]) + @test isapprox(pts[2,:],[0.5,0.5]) + @test isapprox(pts[3,:],[1.0,1.0]) + end + + @testset "CircularArc Tests" begin + center = [0.0,0.0,0.0] + radius = 2.0 + startAngleD = 0.0 + endAngleD = 180.0 + name = "CircularArcCurve" + + crv = new(name, center, radius, startAngleD, endAngleD, "degrees") + + @test typeof(crv) == Dict{String,Any} + @test getCurveType(crv) == "CIRCULAR_ARC" + @test getCurveName(crv) == name + @test getArcCenter(crv) == center + @test getArcRadius(crv) == radius + @test getArcStartAngle(crv) == startAngleD + @test getArcUnits(crv) == "degrees" + + pt = curvePoint(crv, 0.5) + @test isapprox(pt,[0.0,2.0,0.0]) + + pts = curvePoints(crv,2) + @test isapprox(pts[1,:],[2.0,0.0]) + @test isapprox(pts[2,:],[0.0,2.0]) + @test isapprox(pts[3,:],[-2.0,0.0]) + end + + @testset "Spline Tests" begin + nKnots = 5 + nPts = 3 + data = zeros(Float64,nKnots,4) + for j in 1:5 + tj = 0.25*(j-1) + xj = tj^3 + yj = tj^3 + tj^2 + zj = 0.0 + data[j,:] = [tj,xj,yj,zj] + end + + name = "Spline Curve" + crv = newSplineCurve(name, nKnots, data) + + @test typeof(crv) == Dict{String,Any} + @test getCurveType(crv) == "SPLINE_CURVE" + @test getCurveName(crv) == name + + pt = curvePoint(crv, 0.5) + @test isapprox(pt,[0.5^3,0.5^3 + 0.5^2,0.0]) + pt = curvePoint(crv, 0.0) + @test isapprox(pt,[0.0,0.0,0.0]) +# +# The curvePoints for the spline has M = max(N,nKnots*2) values +# + M = max(nPts,nKnots*2) + pts = curvePoints(crv,M) + d = 1.0/M + for j in 1:M+1 + tj = (j-1)*d + @test isapprox(pts[j,:],[tj^3,tj^3 + tj^2]) + end + + end + +end diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl new file mode 100644 index 00000000..593741cc --- /dev/null +++ b/src/Test/Tests.jl @@ -0,0 +1,31 @@ +#= + MIT License + + Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + --- End License +=# + +#= +Set up the test cases for HQMTool +=# +using Test +include("../HQMTool.jl") diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index b557d035..5dc33818 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -23,6 +23,7 @@ --- End License =# +using GLMakie const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 const REFINEMENTS = 8; const ALL = 15 From 8ae2f295b68add11165337c557ee55a295009953 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Sun, 20 Mar 2022 14:42:19 -0700 Subject: [PATCH 008/164] Add API tests Add tests for background grid, run parameters, smoother. --- src/Project/BackgroundGridAPI.jl | 16 ++-- src/Project/Project.jl | 2 +- src/Project/RunParametersAPI.jl | 39 ++++----- src/Project/SmootherAPI.jl | 8 +- src/Test/BackgroundGridTests.jl | 42 ++++++++++ src/Test/CurveTests.jl | 8 +- src/Test/ProjectTests.jl | 35 ++++++++ src/Test/RunParametersTests.jl | 42 ++++++++++ src/Test/SmootherTests.jl | 36 +++++++++ src/Test/TestData/AllFeatures.control | 112 ++++++++++++++++++++++++++ src/Test/TestData/TestProject.control | 15 ++++ src/Test/Tests.jl | 3 + 12 files changed, 321 insertions(+), 37 deletions(-) create mode 100644 src/Test/BackgroundGridTests.jl create mode 100644 src/Test/ProjectTests.jl create mode 100644 src/Test/RunParametersTests.jl create mode 100644 src/Test/SmootherTests.jl create mode 100644 src/Test/TestData/AllFeatures.control create mode 100644 src/Test/TestData/TestProject.control diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 687038af..420c9a92 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -33,7 +33,6 @@ is an outer boundary defined in the model. function addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) disableUndo() disableNotifications() - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") setBackgroundGridSize!(proj, bgSize, "background grid size") enableUndo() registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") @@ -48,7 +47,6 @@ and the number of intervals in each diredction. Use this when there is _no_ outer boundary defined in the model. """ function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") disableUndo() disableNotifications() proj.bounds = box @@ -90,10 +88,10 @@ function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64 setBackgroundGridSize!(proj, dx, "dx") setBackgroundGridLowerLeft!(proj,x0) setBackgroundGridSteps!(proj,N) - proj.userBounds[TOP] = x0[2] + N*dx[2] + proj.userBounds[TOP] = x0[2] + N[2]*dx[2] proj.userBounds[LEFT] = x0[1] proj.userBounds[BOTTOM] = x0[2] - proj.userBounds[RIGHT] = x0[1] + N*dx[1] + proj.userBounds[RIGHT] = x0[1] + N[1]*dx[1] enableUndo() enableNotifications() registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") @@ -109,7 +107,7 @@ Remove the background grid block from the project. function removeBackgroundGrid!(proj::Project) cDict = getControlDict(proj) registerWithUndoManager(proj,addBackgroundGrid!,(cDict,),"Delete Background Grid") - delete!(cDict,"RUN_PARAMETERS") + delete!(cDict,"BACKGROUND_GRID") postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing end @@ -162,7 +160,7 @@ end """ function getBackgroundGridLowerLeft(proj::Project) -Returns the [x,y] of the lower left point of thebackground grid. +Returns the [x,y] of the lower left point of the background grid. """ function getBackgroundGridLowerLeft(proj::Project) bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") @@ -173,14 +171,14 @@ function getBackgroundGridLowerLeft(proj::Project) end end """ - function getBackgroundGridLowerLeft(proj::Project) + function getBackgroundGridSteps(proj::Project) -Returns the [x,y,z] of the lower left point of thebackground grid. +Returns the [Nx,Ny,Nz] for the background grid. """ function getBackgroundGridSteps(proj::Project) bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") if haskey(bgDict,"N") - return realIntForKeyFromDictionary("N",bgDict) + return intArrayForKeyFromDictionary("N",bgDict) else return nothing end diff --git a/src/Project/Project.jl b/src/Project/Project.jl index b64c83fa..98fd4428 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -56,7 +56,7 @@ mutable struct Project end defaultPlotPts = 50 -meshFileFormats = Set(["ISM", "ISM-V2"]) +meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) plotFileFormats = Set(["sem", "skeleton"]) smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) statusValues = Set(["ON", "OFF"]) diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index cd51b452..56e19c9d 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -81,25 +81,6 @@ stats files. function getName(proj::Project) return proj.name end -""" -setFolder(proj::Project,folder::String) - -Set the path to the directory where the mesh, plot, control, and stats files -will be written -""" -function setFolder(proj::Project,folder::String) - oldPath = proj.path - registerWithUndoManager(proj,setFolder,(oldPath,),"Set Project Folder") - proj.path = folder -end -""" - path(proj::Project) - -Returns the directory where the project files will be written -""" -function getfolder(proj::Project) - return proj.path -end """ setPolynomialOrder(proj::Project, p::Int) @@ -121,17 +102,17 @@ Returns the polynomial order for boundary curves in the mesh file. """ function getPolynomialOrder(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return rpDict["polynomial order"] + return parse(Int,rpDict["polynomial order"]) end """ setMeshFileFormat(proj::Project, meshFileFormat::String) Set the file format for the mesh file. Acceptable choices -are "ISM" and "ISM-V2". +are "ISM", "ISM-V2", or "ABAQUS". """ function setMeshFileFormat!(proj::Project, meshFileFormat::String) if !in(meshFileFormat,meshFileFormats) - println("Acceptable file formats are ISM and ISM-V2. Try again.") + println("Acceptable file formats are: ", meshFileFormats,". Try again.") #TODO Format this nicely return end key = "mesh file format" @@ -159,6 +140,10 @@ are "sem", which includes interior nodes and boundary nodes and "skeleton", whic only the corner nodes. """ function setPlotFileFormat!(proj::Project, plotFileFormat::String) + if !in(plotFileFormat,plotFileFormats) + println("Acceptable plot formats are: ", plotFileFormats,". Try again.") #TODO Format this nicely + return + end rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") key = "plot file format" if haskey(rpDict,key) @@ -188,3 +173,13 @@ function setFileNames!(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["mesh file name"] end + + function getPlotFileName(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["plot file name"] + end + + function getStatsFileName(proj::Project) + rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") + return rpDict["stats file name"] + end diff --git a/src/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl index eb046084..8abe1f0d 100644 --- a/src/Project/SmootherAPI.jl +++ b/src/Project/SmootherAPI.jl @@ -35,11 +35,11 @@ function addSpringSmoother!(proj::Project,status::String = "ON", type::String = "LinearAndCrossbarSpring", nIterations::Int = 25) if !in(status,statusValues) - println("Acceptable smoother status are `ON` and `OFF`. Try again.") + println("Acceptable smoother status are: ", statusValues,". Try again.") return end if !in(type,smootherTypes) - println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + println("Acceptable smoothers are:", smootherTypes, ". Try again.") return end setSmoothingStatus!(proj,status) @@ -53,7 +53,7 @@ status is either "ON" or "OFF" """ function setSmoothingStatus!(proj::Project, status::String) if !in(status,statusValues) - println("Acceptable smoother status are `ON` and `OFF`. Try again.") + println("Acceptable smoother status is one of: ", statusValues,". Try again.") return end smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") @@ -75,7 +75,7 @@ type is either `LinearSpring` or `LinearAndCrossbarSpring` """ function setSmoothingType!(proj::Project, type::String) if !in(type,smootherTypes) - println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") + println("Acceptable smoothers are:", smootherTypes, ". Try again.") return end smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") diff --git a/src/Test/BackgroundGridTests.jl b/src/Test/BackgroundGridTests.jl new file mode 100644 index 00000000..6ea493bb --- /dev/null +++ b/src/Test/BackgroundGridTests.jl @@ -0,0 +1,42 @@ +using Test +include("../HQMTool.jl") +# +# Background Grid Tests tests the "BackgroundGrid.jl" functions +# +@testset "Background Grid Tests" begin + + projectName = "TestProject" + projectPath = "./Test/TestData" + + p = newProject(projectName, projectPath) + + @test hasBackgroundGrid(p) == false + addBackgroundGrid!(p,[0.1,0.2,0.0]) + @test hasBackgroundGrid(p) == true + bgs = getBackgroundGridSize(p) + @test isapprox(bgs,[0.1,0.2,0.0]) + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false + + addBackgroundGrid!(p,[-1.0,-1.0,0.0],[0.1,0.1,0.0], [10,10,0]) + @test hasBackgroundGrid(p) == true + @test getBackgroundGridSteps(p) == [10,10,0] + @test isapprox(getBackgroundGridSize(p),[0.1,0.1,0.0]) + @test isapprox(getBackgroundGridLowerLeft(p),[-1.0,-1.0,0.0]) + + undo() + @test hasBackgroundGrid(p) == false + redo() + @test hasBackgroundGrid(p) == true + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false + + addBackgroundGrid!(p, [10.0,-10.0,-5.0,5.0], [10,10,0]) + @test hasBackgroundGrid(p) == true + @test getBackgroundGridSteps(p) == [10,10,0] + @test isapprox(getBackgroundGridSize(p),[1.5,1.5,0.0]) + @test isapprox(getBackgroundGridLowerLeft(p),[-10.0,-5.0,0.0]) + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false + +end diff --git a/src/Test/CurveTests.jl b/src/Test/CurveTests.jl index 06c57ee4..3a58a15b 100644 --- a/src/Test/CurveTests.jl +++ b/src/Test/CurveTests.jl @@ -1,5 +1,8 @@ using Test include("../HQMTool.jl") +# +# Curve Tests tests the "CurvesAPI.jl" functions +# @testset "Curve Tests" begin @testset "ParametricCurve Tests" begin @@ -92,6 +95,7 @@ include("../HQMTool.jl") @test typeof(crv) == Dict{String,Any} @test getCurveType(crv) == "SPLINE_CURVE" @test getCurveName(crv) == name + @test getSplineNKnots(crv) == nKnots pt = curvePoint(crv, 0.5) @test isapprox(pt,[0.5^3,0.5^3 + 0.5^2,0.0]) @@ -107,7 +111,9 @@ include("../HQMTool.jl") tj = (j-1)*d @test isapprox(pts[j,:],[tj^3,tj^3 + tj^2]) end - + + gPts = getSplinePoints(crv) + @test isapprox(data,gPts) end end diff --git a/src/Test/ProjectTests.jl b/src/Test/ProjectTests.jl new file mode 100644 index 00000000..eed6f35c --- /dev/null +++ b/src/Test/ProjectTests.jl @@ -0,0 +1,35 @@ +using Test +include("../HQMTool.jl") +# +# Project Tests tests the "Project.jl" functions +# +@testset "Project Tests" begin +# +# Create, save, and read +# + projectName = "TestProject" + projectPath = "./Test/TestData" + + p = newProject(projectName, projectPath) + + saveProject(p) + q = openProject("TestProject.Control",projectPath) + setSmoothingIterations!(q,25) + + @test getSmoothingIterations(q) == 25 + @test getSmoothingStatus(q) == "ON" + @test getSmoothingType(q) == "LinearAndCrossbarSpring" + + cDict = getControlDict(q) + @test haskey(cDict,"SPRING_SMOOTHER") == true + removeSpringSmoother!(q) + cDict = getControlDict(q) + @test haskey(cDict,"SPRING_SMOOTHER") == false + + + + # p = openProject("AllFeatures.control",projectPath) + + # @test hasBackgroundGrid(p) == true + +end diff --git a/src/Test/RunParametersTests.jl b/src/Test/RunParametersTests.jl new file mode 100644 index 00000000..04256660 --- /dev/null +++ b/src/Test/RunParametersTests.jl @@ -0,0 +1,42 @@ +using Test +include("../HQMTool.jl") +# +# Run Parameters Tests tests the "BackgroundGrid.jl" functions +# +@testset "Run Parameters Tests" begin + + projectName = "TestProject" + projectPath = "./Test/TestData" + newName = "RPTestsName" + + p = newProject(projectName, projectPath) + + @test getName(p) == projectName + setName!(p,newName) + @test getName(p) == newName + setFileNames!(p) + @test getMeshFileName(p) == "./Test/TestData/RPTestsName.mesh" + @test getPlotFileName(p) == "./Test/TestData/RPTestsName.tec" + @test getStatsFileName(p) == "./Test/TestData/RPTestsName.txt" + + @test getPolynomialOrder(p) == 5 + setPolynomialOrder!(p,6) + @test getPolynomialOrder(p) == 6 + + @test getMeshFileFormat(p) == "ISM-V2" + setMeshFileFormat!(p,"ISM") + @test getMeshFileFormat(p) == "ISM" + setMeshFileFormat!(p,"BLORP") + @test getMeshFileFormat(p) == "ISM" + + @test getPlotFileFormat(p) == "skeleton" + setPlotFileFormat!(p,"sem") + @test getPlotFileFormat(p) == "sem" + setPlotFileFormat!(p,"BLORP") + @test getPlotFileFormat(p) == "sem" + + removeRunParameters!(p) + cDict = getControlDict(p) + @test haskey(cDict,"RUN_PARAMETERS") == false + +end diff --git a/src/Test/SmootherTests.jl b/src/Test/SmootherTests.jl new file mode 100644 index 00000000..757a3865 --- /dev/null +++ b/src/Test/SmootherTests.jl @@ -0,0 +1,36 @@ +using Test +include("../HQMTool.jl") +# +# Smoother Tests tests the "SmootherAPI.jl" functions +# +@testset "Smoother Tests" begin +# +# Create, save, and read +# + projectName = "TestProject" + projectPath = "./Test/TestData" + + p = newProject(projectName, projectPath) + + saveProject(p) + q = openProject("TestProject.Control",projectPath) + setSmoothingIterations!(q,25) + + @test getSmoothingIterations(q) == 25 + @test getSmoothingStatus(q) == "ON" + @test getSmoothingType(q) == "LinearAndCrossbarSpring" + + setSmoothingStatus!(q,"OFF") + @test getSmoothingStatus(q) == "OFF" + setSmoothingStatus!(q,"UNKNOWN") + @test getSmoothingStatus(q) == "OFF" + setSmoothingType!(q,"LinearSpring") + @test getSmoothingType(q) == "LinearSpring" + + cDict = getControlDict(q) + @test haskey(cDict,"SPRING_SMOOTHER") == true + removeSpringSmoother!(q) + cDict = getControlDict(q) + @test haskey(cDict,"SPRING_SMOOTHER") == false + +end diff --git a/src/Test/TestData/AllFeatures.control b/src/Test/TestData/AllFeatures.control new file mode 100644 index 00000000..8244db77 --- /dev/null +++ b/src/Test/TestData/AllFeatures.control @@ -0,0 +1,112 @@ +\begin{MODEL} + \begin{OUTER_BOUNDARY} + \begin{END_POINTS_LINE} + name = B1 + xEnd = [20.0,-5,0.0] + xStart = [-20.0,-5.0,0.0] + \end{END_POINTS_LINE} + \begin{END_POINTS_LINE} + name = B2 + xEnd = [0.0,25.28,0.0] + xStart = [20.0,-5.0,0.0] + \end{END_POINTS_LINE} + \begin{END_POINTS_LINE} + name = B3 + xEnd = [-20.0,-5.0,0.0] + xStart = [0.0,25.28,0.0] + \end{END_POINTS_LINE} + \end{OUTER_BOUNDARY} + \begin{INNER_BOUNDARIES} + \begin{CHAIN} + name = Arc + \begin{CIRCULAR_ARC} + units = degrees + name = InnerCircle1 + radius = 1.0 + start angle = 0.0 + center = [-12.0,-1.5,0.0] + end angle = 360.0 + \end{CIRCULAR_ARC} + \end{CHAIN} + \begin{CHAIN} + name = InnerSpline + \begin{SPLINE_CURVE} + name = Spline + nKnots = 26 + \begin{SPLINE_DATA} + 0.0 -3.5 3.5 0.0 + 0.03846153846153846 -3.2 5.0 0.0 + 0.07692307692307693 -2.0 6.0 0.0 + 0.115384615384615 1.0 6.0 0.0 + 0.153846153846154 2.0 5.0 0.0 + 0.192307692307692 3.0 4.0 0.0 + 0.230769230769231 5.0 4.0 0.0 + 0.269230769230769 6.0 5.0 0.0 + 0.307692307692308 7.0 7.0 0.0 + 0.346153846153846 8.0 8.0 0.0 + 0.384615384615385 9.0 8.0 0.0 + 0.423076923076923 10.0 7.0 0.0 + 0.461538461538462 11.0 5.0 0.0 + 0.5 11.0 3.0 0.0 + 0.538461538461539 10.0 2.0 0.0 + 0.576923076923077 9.0 1.0 0.0 + 0.615384615384615 7.0 1.0 0.0 + 0.653846153846154 5.0 1.0 0.0 + 0.692307692307692 3.0 1.0 0.0 + 0.730769230769231 1.0 0.0 0.0 + 0.769230769230769 0.0 -1.0 0.0 + 0.807692307692308 -1.0 -1.0 0.0 + 0.846153846153846 -2.0 -0.8 0.0 + 0.884615384615385 -2.5 0.0 0.0 + 0.923076923076923 -3.0 1.0 0.0 + 1.0 -3.5 3.5 0.0 + \end{SPLINE_DATA} + \end{SPLINE_CURVE} + \end{CHAIN} + \begin{CHAIN} + name = InnerCircle2 + \begin{PARAMETRIC_EQUATION_CURVE} + name = Circle1 + yEqn = f(t) = 17.0 + 1.5*sin(2*pi*t) + zEqn = z(t) = 0.0 + xEqn = f(t) = 1.5*cos(2*pi*t) + \end{PARAMETRIC_EQUATION_CURVE} + \end{CHAIN} + \end{INNER_BOUNDARIES} +\end{MODEL} +\begin{CONTROL_INPUT} + \begin{REFINEMENT_REGIONS} + \begin{REFINEMENT_CENTER} + name = center + w = 0.5 + x0 = [9.0,-3.0,0.0] + type = smooth + h = 0.1 + \end{REFINEMENT_CENTER} + \begin{REFINEMENT_LINE} + name = line + x1 = [2.0,14.0,0.0] + w = 0.5 + x0 = [-6.0,9.0,0.0] + type = smooth + h = 0.2 + \end{REFINEMENT_LINE} + \end{REFINEMENT_REGIONS} + \begin{SPRING_SMOOTHER} + smoothing type = LinearAndCrossbarSpring + smoothing = ON + number of iterations = 25 + \end{SPRING_SMOOTHER} + \begin{BACKGROUND_GRID} + background grid size = [3.0,3.0,0.0] + \end{BACKGROUND_GRID} + \begin{RUN_PARAMETERS} + mesh file name = examples/AllFeatures.mesh + plot file format = skeleton + plot file name = examples/AllFeatures.tec + stats file name = none + mesh file format = ISM-V2 + polynomial order = 4 + \end{RUN_PARAMETERS} +\end{CONTROL_INPUT} +\end{FILE} diff --git a/src/Test/TestData/TestProject.control b/src/Test/TestData/TestProject.control new file mode 100644 index 00000000..d897d338 --- /dev/null +++ b/src/Test/TestData/TestProject.control @@ -0,0 +1,15 @@ +\begin{CONTROL_INPUT} + \begin{SPRING_SMOOTHER} + smoothing type = LinearAndCrossbarSpring + smoothing = ON + \end{SPRING_SMOOTHER} + \begin{RUN_PARAMETERS} + mesh file name = ./Test/TestData/TestProject.mesh + plot file format = skeleton + plot file name = ./Test/TestData/TestProject.tec + stats file name = ./Test/TestData/TestProject.txt + mesh file format = ISM-V2 + polynomial order = 5 + \end{RUN_PARAMETERS} +\end{CONTROL_INPUT} +\end{FILE} diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl index 593741cc..84d12043 100644 --- a/src/Test/Tests.jl +++ b/src/Test/Tests.jl @@ -29,3 +29,6 @@ Set up the test cases for HQMTool =# using Test include("../HQMTool.jl") +include("CurveTests.jl") +include("BackgroundGridTests.jl") +include("ProjectTests.jl") From 409344302fd24b6008f01bad4d371a343c9e1251 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Mon, 21 Mar 2022 13:22:47 -0700 Subject: [PATCH 009/164] Add Refinement Tests Add tests for refinement regions. fix exposed bugs. --- src/Project/RefinementRegionsAPI.jl | 10 ++--- src/Test/RefinementTests.jl | 70 +++++++++++++++++++++++++++++ src/Test/Tests.jl | 3 ++ 3 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/Test/RefinementTests.jl diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 1c439034..f44ab238 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -184,11 +184,11 @@ function newRefinementLine(name::String, type::String, disableNotifications() lineDict = Dict{String,Any}() lineDict["TYPE"] = "REFINEMENT_LINE" - setRefinementType(lineDict,type) - setRefinementStart(lineDict,x0) - setRefinementEnd(lineDict,x1) - setRefinementGridSize(lineDict,h) - setRefinementWidth(lineDict,w) + setRefinementType!(lineDict,type) + setRefinementStart!(lineDict,x0) + setRefinementEnd!(lineDict,x1) + setRefinementGridSize!(lineDict,h) + setRefinementWidth!(lineDict,w) setRefinementName!(lineDict,name) enableNotifications() enableUndo() diff --git a/src/Test/RefinementTests.jl b/src/Test/RefinementTests.jl new file mode 100644 index 00000000..192d3994 --- /dev/null +++ b/src/Test/RefinementTests.jl @@ -0,0 +1,70 @@ +using Test +include("../HQMTool.jl") +# +# Project Tests tests the "Project.jl" functions +# +@testset "Project Tests" begin + + projectName = "TestProject" + projectPath = "./Test/TestData" + + p = newProject(projectName, projectPath) + disableNotifications() + + x0 = [1.0,2.0,0.0] + h = 0.25 + w = 0.5 + + cent1 = newRefinementCenter("Center1","smooth",x0,h,w) + disableNotifications() + + @test getRefinementType(cent1) == "smooth" + setRefinementType!(cent1,"sharp") + @test getRefinementType(cent1) == "sharp" + undo() + @test getRefinementType(cent1) == "smooth" + redo() + @test getRefinementType(cent1) == "sharp" + + @test getRefinementName(cent1) == "Center1" + setRefinementName!(cent1,"Second") + @test getRefinementName(cent1) == "Second" + undo() + @test getRefinementName(cent1) == "Center1" + redo() + @test getRefinementName(cent1) == "Second" + undo() + @test getRefinementName(cent1) == "Center1" + + @test getRefinementLocation(cent1) == x0 + @test getRefinementWidth(cent1) == w + @test getRefinementGridSize(cent1) == h + + setRefinementGridSize!(cent1,0.5) + @test getRefinementGridSize(cent1) == 0.5 + undo() + @test getRefinementGridSize(cent1) == h + redo() + @test getRefinementGridSize(cent1) == 0.5 + + setRefinementLocation!(cent1,[0.0,0.0,0.0]) + @test getRefinementLocation(cent1) == [0.0,0.0,0.0] + undo() + @test getRefinementLocation(cent1) == x0 + redo() + @test getRefinementLocation(cent1) == [0.0,0.0,0.0] + + line1 = newRefinementLine("Line1","smooth",[1.0,0.5,0.0],[1.5,2.0,0.0],h,w) + disableNotifications() + + @test getRefinementType(line1) == "smooth" + @test getRefinementName(line1) == "Line1" + @test getRefinementWidth(line1) == w + @test getRefinementGridSize(line1) == h + @test isapprox(getRefinementStart(line1),[1.0,0.5,0.0]) + @test isapprox(getRefinementEnd(line1),[1.5,2.0,0.0]) + + setRefinementGridSize!(cent1,0.5) + + enableNotifications() +end diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl index 84d12043..2c529195 100644 --- a/src/Test/Tests.jl +++ b/src/Test/Tests.jl @@ -32,3 +32,6 @@ include("../HQMTool.jl") include("CurveTests.jl") include("BackgroundGridTests.jl") include("ProjectTests.jl") +include("SmootherTests.jl") +include("RunParametersTests.jl") +include("RefinementTests.jl") From 0296c84b61643af71dbc69c898bb66a6f8b8fea5 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Mon, 21 Mar 2022 18:07:33 -0700 Subject: [PATCH 010/164] More refinement tests Add more refinement tests and associated bug fixes. --- src/HOHQMesh.jl | 2 +- src/Project/Project.jl | 2 +- src/Project/RefinementRegionsAPI.jl | 44 +++++------ src/Test/BackgroundGridTests.jl | 20 ++++- src/Test/RefinementTests.jl | 117 ++++++++++++++++++++++------ 5 files changed, 130 insertions(+), 55 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 19cdb701..39bdbd7b 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -129,6 +129,6 @@ examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") # FIXME: Include this in a proper way -include("HQMTool.jl") +# include("HQMTool.jl") end # module diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 98fd4428..48642fd5 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -373,7 +373,7 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) x = refinementRegionPoints(sender) proj.refinementRegionPoints[indx] = x proj.refinementRegionNames[indx] = sender["name"] - center = refinementRegionCenter(sender) + center = getRefinementRegionCenter(sender) proj.refinementRegionLoc[indx] = center if !isnothing(proj.plt) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index f44ab238..0340c155 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -72,7 +72,7 @@ function addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) x = refinementRegionPoints(r) push!(proj.refinementRegionPoints,x) push!(proj.refinementRegionNames, r["name"]) - center = refinementRegionCenter(r) + center = getRefinementRegionCenter(r) push!(proj.refinementRegionLoc,center) end """ @@ -117,11 +117,11 @@ function refinementRegionPoints(r::Dict{String,Any}) end """ - refinementRegionCenter(r::Dict{String,Any}) + getRefinementRegionCenter(r::Dict{String,Any}) Get, or compute, the center of the given refinement region. """ -function refinementRegionCenter(r::Dict{String,Any}) +function getRefinementRegionCenter(r::Dict{String,Any}) if r["TYPE"] == "REFINEMENT_CENTER" center = getRefinementLocation(r) return center[1:2] @@ -159,7 +159,7 @@ function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) insert!(lst,indx,r) x = refinementRegionPoints(r) insert!(proj.refinementRegionPoints,indx,x) - center = refinementRegionCenter(r) + center = getRefinementRegionCenter(r) insert!(proj.refinementRegionLoc,indx,center) insert!(proj.refinementRegionNames,indx,r["name"]) postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) @@ -215,7 +215,7 @@ end # -------------------------------------------------------------------------------------- # """ - allRefinementRegions(proj::Project) + getAllRefinementRegions(proj::Project) Get the list of refinement regions. """ @@ -307,13 +307,8 @@ end# Set the location of a refinement center to location = [x,y,z]. """ function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") - end x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x0"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) + setRefinementLocation!(r,x0Str) return nothing end @@ -324,6 +319,7 @@ function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) end r["x0"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) + return nothing end # # -------------------------------------------------------------------------------------- @@ -341,7 +337,7 @@ end # -------------------------------------------------------------------------------------- # """ - setRefinementGridSize(r::Dict{String,Any}, h) + setRefinementGridSize!(r::Dict{String,Any}, h) Set the grid size, `h` for the refinement region. `r` is the dictionary that represents the refinement region. @@ -352,7 +348,9 @@ function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") end r["h"] = string(h) + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end + function setRefinementGridSize!(r::Dict{String,Any}, h::String) hf = parse(Float64,h) setRefinementGridSize!(r,hf) @@ -386,6 +384,7 @@ function setRefinementWidth!(r::Dict{String,Any},w::Float64) r["w"] = string(w) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end + function setRefinementWidth!(r::Dict{String,Any},w::String) wf = parse(Float64,w) setRefinementWidth!(r,wf) @@ -411,20 +410,17 @@ end Set the start point location of a refinement line, `location = [x, y, z]`. """ function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") - end x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x0"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(r,)) + setRefinementStart!(r,x0Str) end + function setRefinementStart!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x0") old = r["x0"] registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") end r["x0"] = x0Str + postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end # # -------------------------------------------------------------------------------------- @@ -442,23 +438,19 @@ end # -------------------------------------------------------------------------------------- # """ - setRefinementEnd(refinementRegion, location) + setRefinementEnd!(refinementRegion, location) Set the end point location of a refinement line, `location = [x, y, z]`. """ function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x1") - old = r["x1"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") - end x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x1"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) + setRefinementEnd!(r,x0Str) end + function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x1") old = r["x1"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") + registerWithUndoManager(r,setRefinementEnd!, (old,), "Set Refinement End") end r["x1"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) diff --git a/src/Test/BackgroundGridTests.jl b/src/Test/BackgroundGridTests.jl index 6ea493bb..df361816 100644 --- a/src/Test/BackgroundGridTests.jl +++ b/src/Test/BackgroundGridTests.jl @@ -1,8 +1,22 @@ using Test include("../HQMTool.jl") -# -# Background Grid Tests tests the "BackgroundGrid.jl" functions -# +#= + Background Grid Tests tests the "BackgroundGrid.jl" functions + +Functions: @ = tested + @ addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + @ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + @ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + @ removeBackgroundGrid!(proj::Project) + setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + @ getBackgroundGridSize(proj::Project) + @ getBackgroundGridLowerLeft(proj::Project) + @ getBackgroundGridSteps(proj::Project) + setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + setBackgroundGridSteps!(proj::Project, N::Array{Int}) + setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) +=# @testset "Background Grid Tests" begin projectName = "TestProject" diff --git a/src/Test/RefinementTests.jl b/src/Test/RefinementTests.jl index 192d3994..f947979d 100644 --- a/src/Test/RefinementTests.jl +++ b/src/Test/RefinementTests.jl @@ -1,23 +1,55 @@ using Test include("../HQMTool.jl") -# -# Project Tests tests the "Project.jl" functions -# +#= + Project Tests tests the "Project.jl" functions +Functions: @ = tested + @ newRefinementCenter + @ addRefinementRegion! + addRefinementRegionPoints! + refinementRegionPoints + @ getRefinementRegionCenter + removeRefinementRegion! + insertRefinementRegion! + @ newRefinementLine + getRefinementRegion (1) + getAllRefinementRegions + getRefinementRegion (2) + @ setRefinementType! + @ getRefinementType + @ setRefinementName! + @ getRefinementName + @ setRefinementLocation! + @ getRefinementLocation + @ setRefinementGridSize! + @ getRefinementGridSize + @ setRefinementWidth! + @ getRefinementWidth + @ setRefinementStart! + @ getRefinementStart + @ setRefinementEnd! + @ getRefinementEnd +=# @testset "Project Tests" begin projectName = "TestProject" projectPath = "./Test/TestData" p = newProject(projectName, projectPath) - disableNotifications() - +# +# Creating and changing refinement regions... +# x0 = [1.0,2.0,0.0] h = 0.25 w = 0.5 - +# +# ...Center +# cent1 = newRefinementCenter("Center1","smooth",x0,h,w) - disableNotifications() - + addRefinementRegion!(p,cent1) + @test length(p.refinementRegionNames) == 1 +# +# Refinement type +# @test getRefinementType(cent1) == "smooth" setRefinementType!(cent1,"sharp") @test getRefinementType(cent1) == "sharp" @@ -25,7 +57,9 @@ include("../HQMTool.jl") @test getRefinementType(cent1) == "smooth" redo() @test getRefinementType(cent1) == "sharp" - +# +# Refinement name +# @test getRefinementName(cent1) == "Center1" setRefinementName!(cent1,"Second") @test getRefinementName(cent1) == "Second" @@ -35,36 +69,71 @@ include("../HQMTool.jl") @test getRefinementName(cent1) == "Second" undo() @test getRefinementName(cent1) == "Center1" - +# +# Refinement center location +# + @test getRefinementLocation(cent1) == x0 + @test getRefinementRegionCenter(cent1) == [1.0,2.0] + setRefinementLocation!(cent1,[0.,0.,0.]) + @test getRefinementLocation(cent1) == [0.,0.,0.] + undo() @test getRefinementLocation(cent1) == x0 + redo() + @test getRefinementLocation(cent1) == [0.,0.,0.] +# +# Refinement width +# @test getRefinementWidth(cent1) == w + setRefinementWidth!(cent1,1.0) + @test getRefinementWidth(cent1) == 1.0 + undo() + @test getRefinementWidth(cent1) == w + redo() + @test getRefinementWidth(cent1) == 1.0 +# +# Refinement grid size +# @test getRefinementGridSize(cent1) == h - setRefinementGridSize!(cent1,0.5) @test getRefinementGridSize(cent1) == 0.5 undo() @test getRefinementGridSize(cent1) == h redo() @test getRefinementGridSize(cent1) == 0.5 - - setRefinementLocation!(cent1,[0.0,0.0,0.0]) - @test getRefinementLocation(cent1) == [0.0,0.0,0.0] - undo() - @test getRefinementLocation(cent1) == x0 - redo() - @test getRefinementLocation(cent1) == [0.0,0.0,0.0] - +# +#... Line +# line1 = newRefinementLine("Line1","smooth",[1.0,0.5,0.0],[1.5,2.0,0.0],h,w) - disableNotifications() - + addRefinementRegion!(p,line1) + @test length(p.refinementRegionNames) == 2 + #the following have been tested above @test getRefinementType(line1) == "smooth" @test getRefinementName(line1) == "Line1" @test getRefinementWidth(line1) == w @test getRefinementGridSize(line1) == h +# +# Refinement line start +# @test isapprox(getRefinementStart(line1),[1.0,0.5,0.0]) + setRefinementStart!(line1,[0.0,0.0,0.0]) + @test getRefinementStart(line1) == [0.0,0.0,0.0] + undo() + @test isapprox(getRefinementStart(line1),[1.0,0.5,0.0]) + redo() + @test getRefinementStart(line1) == [0.0,0.0,0.0] +# +# Refinement Line End +# @test isapprox(getRefinementEnd(line1),[1.5,2.0,0.0]) - - setRefinementGridSize!(cent1,0.5) + setRefinementEnd!(line1,[0.0,0.0,0.0]) + @test getRefinementEnd(line1) == [0.0,0.0,0.0] + undo() + @test isapprox(getRefinementEnd(line1),[1.5,2.0,0.0]) + redo() + @test getRefinementEnd(line1) == [0.0,0.0,0.0] +# +# Project functions +# + - enableNotifications() end From 8c50f6a2a68f3b1ebe0825d30ba6fda6813f2a4a Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 22 Mar 2022 10:04:56 -0700 Subject: [PATCH 011/164] Update RefinementTests.jl Cover all but two (plotting point) methods. --- src/Test/RefinementTests.jl | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Test/RefinementTests.jl b/src/Test/RefinementTests.jl index f947979d..0acc099b 100644 --- a/src/Test/RefinementTests.jl +++ b/src/Test/RefinementTests.jl @@ -8,12 +8,12 @@ Functions: @ = tested addRefinementRegionPoints! refinementRegionPoints @ getRefinementRegionCenter - removeRefinementRegion! - insertRefinementRegion! + @ removeRefinementRegion! + @ insertRefinementRegion! @ newRefinementLine - getRefinementRegion (1) - getAllRefinementRegions - getRefinementRegion (2) + @ getRefinementRegion (1) + @ getAllRefinementRegions + @ getRefinementRegion (2) @ setRefinementType! @ getRefinementType @ setRefinementName! @@ -134,6 +134,28 @@ Functions: @ = tested # # Project functions # + lst = getAllRefinementRegions(p) + @test length(lst) == 2 + (i,r) = getRefinementRegion(p,"Line1") + @test i == 2 + @test getRefinementName(r) == "Line1" + s = getRefinementRegion(p,1) + @test getRefinementName(s) == "Center1" + + c2 = newRefinementCenter("middle","smooth",[2.0,3.0,4.0],0.6,3.0) + insertRefinementRegion!(p,c2,2) + lst = getAllRefinementRegions(p) + @test length(lst) == 3 + + removeRefinementRegion!(p,"middle") + lst = getAllRefinementRegions(p) + @test length(lst) == 2 + names = ["Center1", "Line1"] + + for (i,d) in enumerate(lst) + @test getRefinementName(d) == names[i] + end + end From b83619db097a226aeb182a793f3f84c2c5bdfa9d Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 22 Mar 2022 10:33:21 -0700 Subject: [PATCH 012/164] BackgroundGridTests Finish up background grid tests, and fix exposed bugs. --- src/Project/BackgroundGridAPI.jl | 4 ++-- src/Test/BackgroundGridTests.jl | 33 +++++++++++++++++++++++--------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 420c9a92..6338d48a 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -127,8 +127,8 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Flo # With the "corner+intervals" setting of the outer boundary deprecated, keep # the original bounds fixed. x0 = realArrayForKeyFromDictionary("x0",bgDict) - Nx = round(Int,(proj.userBounds[RIGHT] - proj.userBounds[LEFT]) /dx[1]) - Ny = round(Int,(proj.userBounds[TOP] - proj.userBounds[BOTTOM])/dx[2]) + Nx = round(Int,(proj.userBounds[RIGHT] - proj.userBounds[LEFT]) /dx) + Ny = round(Int,(proj.userBounds[TOP] - proj.userBounds[BOTTOM])/dy) N = [Nx,Ny,0] disableNotifications() setBackgroundGridSteps!(proj,N) diff --git a/src/Test/BackgroundGridTests.jl b/src/Test/BackgroundGridTests.jl index df361816..0ee9e499 100644 --- a/src/Test/BackgroundGridTests.jl +++ b/src/Test/BackgroundGridTests.jl @@ -8,14 +8,14 @@ Functions: @ = tested @ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) @ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) @ removeBackgroundGrid!(proj::Project) - setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + @ setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) @ getBackgroundGridSize(proj::Project) @ getBackgroundGridLowerLeft(proj::Project) @ getBackgroundGridSteps(proj::Project) - setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) - setBackgroundGridSteps!(proj::Project, N::Array{Int}) - setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) - addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) + @ setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + @ setBackgroundGridSteps!(proj::Project, N::Array{Int}) + @ setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + @ addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) =# @testset "Background Grid Tests" begin @@ -23,7 +23,9 @@ Functions: @ = tested projectPath = "./Test/TestData" p = newProject(projectName, projectPath) - +# +# Add with method 1 (when outer boundary is present): [dx,dy,dz] +# @test hasBackgroundGrid(p) == false addBackgroundGrid!(p,[0.1,0.2,0.0]) @test hasBackgroundGrid(p) == true @@ -31,25 +33,38 @@ Functions: @ = tested @test isapprox(bgs,[0.1,0.2,0.0]) removeBackgroundGrid!(p) @test hasBackgroundGrid(p) == false - +# +# Add with method 2: lower left, dx, nPts +# addBackgroundGrid!(p,[-1.0,-1.0,0.0],[0.1,0.1,0.0], [10,10,0]) @test hasBackgroundGrid(p) == true @test getBackgroundGridSteps(p) == [10,10,0] @test isapprox(getBackgroundGridSize(p),[0.1,0.1,0.0]) @test isapprox(getBackgroundGridLowerLeft(p),[-1.0,-1.0,0.0]) - +# +# Test undo, redo +# undo() @test hasBackgroundGrid(p) == false redo() @test hasBackgroundGrid(p) == true removeBackgroundGrid!(p) @test hasBackgroundGrid(p) == false - +# +# Add with method 3 (No outer bounday, preferred): bounding box + nPts +# addBackgroundGrid!(p, [10.0,-10.0,-5.0,5.0], [10,10,0]) @test hasBackgroundGrid(p) == true @test getBackgroundGridSteps(p) == [10,10,0] @test isapprox(getBackgroundGridSize(p),[1.5,1.5,0.0]) @test isapprox(getBackgroundGridLowerLeft(p),[-10.0,-5.0,0.0]) +# +# Editing functions +# + setBackgroundGridSize!(p, 1.0, 1.0) + @test isapprox(getBackgroundGridSize(p), [1.0,1.0,0.0]) + @test getBackgroundGridSteps(p) == [15,15,0] + removeBackgroundGrid!(p) @test hasBackgroundGrid(p) == false From fb169f52353db1d4cdc412ba3c70733f8ea47a37 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 22 Mar 2022 10:45:31 -0700 Subject: [PATCH 013/164] Smoother tests Finish up smoother tests. --- src/Project/SmootherAPI.jl | 7 ++++--- src/Test/SmootherTests.jl | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl index 8abe1f0d..87a49631 100644 --- a/src/Project/SmootherAPI.jl +++ b/src/Project/SmootherAPI.jl @@ -82,7 +82,7 @@ function setSmoothingType!(proj::Project, type::String) smDict["smoothing type"] = type end """ - smoothingType(proj::Project) + getSmoothingType(proj::Project) Returns either "LinearSpring" or "LinearAndCrossbarSpring" """ @@ -91,7 +91,7 @@ function getSmoothingType(proj::Project) return smDict["smoothing type"] end """ - setSmoothingIterations!((proj::Project, iterations::Int) + setSmoothingIterations!(proj::Project, iterations::Int) Set the number of iterations to smooth the mesh. """ @@ -100,12 +100,13 @@ function setSmoothingIterations!(proj::Project, iterations::Int) smDict["number of iterations"] = iterations end """ + getSmoothingIterations(proj::Project) +Get the number of iterations to smooth the mesh. """ function getSmoothingIterations(proj::Project) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") return smDict["number of iterations"] - end """ removeSpringSmoother!(proj::Project) diff --git a/src/Test/SmootherTests.jl b/src/Test/SmootherTests.jl index 757a3865..f07c9d61 100644 --- a/src/Test/SmootherTests.jl +++ b/src/Test/SmootherTests.jl @@ -1,8 +1,18 @@ using Test include("../HQMTool.jl") -# -# Smoother Tests tests the "SmootherAPI.jl" functions -# +#= + Smoother Tests tests the "SmootherAPI.jl" functions + +Functions: @ = tested + @ addSpringSmoother!(status::String, type::String, nIterations::Int) + @ setSmoothingStatus!(proj::Project, status::String) + @ getSmoothingStatus(proj::Project) + @ setSmoothingType!(proj::Project, type::String) + @ getSmoothingType(proj::Project) + @ setSmoothingIterations!(proj::Project, iterations::Int) + @ getSmoothingIterations(proj::Project) + @ removeSpringSmoother!(proj::Project) +=# @testset "Smoother Tests" begin # # Create, save, and read From 1c98f771dd1600631470ecf456fca27f39fa14ed Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 22 Mar 2022 11:07:02 -0700 Subject: [PATCH 014/164] Finish Run Parameters Finish up coverage. --- src/Project/RunParametersAPI.jl | 2 +- src/Test/RunParametersTests.jl | 55 ++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index 56e19c9d..23c7fc75 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -50,7 +50,7 @@ end """ removeRunParameters!(proj::Project) -Remove the run parameters block from the project. +Remove the run parameters block from the project. This is not undo-able. """ function removeRunParameters!(proj::Project) cDict = getControlDict(proj) diff --git a/src/Test/RunParametersTests.jl b/src/Test/RunParametersTests.jl index 04256660..362d9a36 100644 --- a/src/Test/RunParametersTests.jl +++ b/src/Test/RunParametersTests.jl @@ -1,37 +1,76 @@ using Test include("../HQMTool.jl") -# -# Run Parameters Tests tests the "BackgroundGrid.jl" functions -# +#= + Run Parameters Tests tests the "RunParameters.jl" functions + +Functions: @ = tested + @ addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) + @ removeRunParameters!(proj::Project) + @ setName!(proj::Project,name::String) + @ getName(proj::Project) + @ setPolynomialOrder!(proj::Project, p::Int) + @ getPolynomialOrder(proj::Project) + @ setMeshFileFormat!(proj::Project, meshFileFormat::String) + @ getMeshFileFormat(proj::Project) + @ setPlotFileFormat!(proj::Project, plotFileFormat::String) + @ getPlotFileFormat(proj::Project) + @ setFileNames!(proj::Project) + @ getMeshFileName(proj::Project) + @ getPlotFileName(proj::Project) + @ getStatsFileName(proj::Project) +=# @testset "Run Parameters Tests" begin projectName = "TestProject" projectPath = "./Test/TestData" newName = "RPTestsName" - p = newProject(projectName, projectPath) + p = newProject(projectName, projectPath) # Auto sets up run parameters - @test getName(p) == projectName + @test getName(p) == projectName setName!(p,newName) - @test getName(p) == newName + @test getName(p) == newName + + undo() + @test getName(p) == projectName + redo() + @test getName(p) == newName + setFileNames!(p) - @test getMeshFileName(p) == "./Test/TestData/RPTestsName.mesh" - @test getPlotFileName(p) == "./Test/TestData/RPTestsName.tec" + @test getMeshFileName(p) == "./Test/TestData/RPTestsName.mesh" + @test getPlotFileName(p) == "./Test/TestData/RPTestsName.tec" @test getStatsFileName(p) == "./Test/TestData/RPTestsName.txt" @test getPolynomialOrder(p) == 5 setPolynomialOrder!(p,6) @test getPolynomialOrder(p) == 6 + undo() + @test getPolynomialOrder(p) == 5 + redo() + @test getPolynomialOrder(p) == 6 @test getMeshFileFormat(p) == "ISM-V2" setMeshFileFormat!(p,"ISM") @test getMeshFileFormat(p) == "ISM" + undo() + @test getMeshFileFormat(p) == "ISM-V2" + redo() + @test getMeshFileFormat(p) == "ISM" + setMeshFileFormat!(p,"BLORP") @test getMeshFileFormat(p) == "ISM" @test getPlotFileFormat(p) == "skeleton" setPlotFileFormat!(p,"sem") @test getPlotFileFormat(p) == "sem" + undo() + @test getPlotFileFormat(p) == "skeleton" + redo() + @test getPlotFileFormat(p) == "sem" + setPlotFileFormat!(p,"BLORP") @test getPlotFileFormat(p) == "sem" From 8f8c1d492474fec61ca7103b5da7ddf05c894597 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 22 Mar 2022 17:05:35 -0700 Subject: [PATCH 015/164] Update Spline tests Add coverage and undo/redo. --- src/Project/CurvesAPI.jl | 31 +++++++------- src/Test/CurveTests.jl | 89 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 299ec15f..0af1ecd0 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -252,16 +252,16 @@ Set the start point for a line curve. """ function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + setStartPoint!(crv,pStr) +end + +function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xStart" if haskey(crv,key) oldPt = crv[key] registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") end - crv[key] = pStr - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) - crv["xStart"] = pointAsString + crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -279,16 +279,16 @@ Set the end point for a line curve. """ function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + setEndPoint!(crv,pStr) +end + +function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xEnd" if haskey(crv,key) oldPt = crv[key] registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") end - crv[key] = pStr - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) - crv["xEnd"] = pointAsString + crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -331,20 +331,19 @@ end Set the center of a circular arc. """ function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + setArcCenter!(arc,pStr) +end +function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) key = "center" if haskey(arc,key) oldVal = arc[key] registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") end - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) - arc[key] = pStr + arc[key] = pointAsString postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end -function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) - arc["center"] = pointAsString - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end """ getArcCenter(crv::Dict{String,Any}, point::Array{Float64}) diff --git a/src/Test/CurveTests.jl b/src/Test/CurveTests.jl index 3a58a15b..4977e470 100644 --- a/src/Test/CurveTests.jl +++ b/src/Test/CurveTests.jl @@ -1,8 +1,55 @@ using Test include("../HQMTool.jl") -# -# Curve Tests tests the "CurvesAPI.jl" functions -# +#= + Curve Tests tests the "CurvesAPI.jl" functions + +Functions: @ = tested + @(as new) newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) + @(as new) newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + @(as new) newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String = "degrees") + @ newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + newSplineCurve(name::String, dataFile::String) + @ setCurveName!(crv::Dict{String,Any}, name::String) + @ getCurveName(crv::Dict{String,Any}) + @ getCurveType(crv::Dict{String,Any}) + @ setXEqn!(crv::Dict{String,Any}, eqn::String) + @ getXEqn(crv::Dict{String,Any}) + @ setYEqn!(crv::Dict{String,Any}, eqn::String) + @ getYEqn(crv::Dict{String,Any}) + @ setZEqn!(crv::Dict{String,Any}, eqn::String) + @ getZEqn(crv::Dict{String,Any}) + @ setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + @ setStartPoint!(crv::Dict{String,Any}, pointAsString::String) + @ getStartPoint(crv::Dict{String,Any}) + @ setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + @ setEndPoint!(crv::Dict{String,Any}, pointAsString::String) + @ getEndPoint(crv::Dict{String,Any}) + @ setArcUnits!(arc::Dict{String,Any}, units::String) + @ getArcUnits(arc::Dict{String,Any}) + @ setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + @ setArcCenter!(arc::Dict{String,Any}, pointAsString::String) + @ getArcCenter(arc::Dict{String,Any}) + @ setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + @ getArcStartAngle(arc::Dict{String,Any}) + @ setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + @ getArcEndAngle(arc::Dict{String,Any}) + @ setArcRadius!(arc::Dict{String,Any}, radius::Float64) + @ getArcRadius(arc::Dict{String,Any}) + @ setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) + @ getSplineNKnots(spline::Dict{String,Any}) + @ setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) + @ getSplinePoints(spline::Dict{String,Any}) +=# @testset "Curve Tests" begin @testset "ParametricCurve Tests" begin @@ -49,6 +96,21 @@ include("../HQMTool.jl") @test isapprox(pts[1,:],[0.0,0.0]) @test isapprox(pts[2,:],[0.5,0.5]) @test isapprox(pts[3,:],[1.0,1.0]) + + setStartPoint!(crv,[2.0,3.0,0.0]) + @test getStartPoint(crv) == [2.0,3.0,0.0] + undo() + @test getStartPoint(crv) == xStart + redo() + @test getStartPoint(crv) == [2.0,3.0,0.0] + + setEndPoint!(crv,[2.0,3.0,0.0]) + @test getEndPoint(crv) == [2.0,3.0,0.0] + undo() + @test getEndPoint(crv) == xEnd + redo() + @test getEndPoint(crv) == [2.0,3.0,0.0] + end @testset "CircularArc Tests" begin @@ -75,6 +137,21 @@ include("../HQMTool.jl") @test isapprox(pts[1,:],[2.0,0.0]) @test isapprox(pts[2,:],[0.0,2.0]) @test isapprox(pts[3,:],[-2.0,0.0]) + + setArcUnits!(crv,"radians") + @test getArcUnits(crv) == "radians" + undo() + @test getArcUnits(crv) == "degrees" + redo() + @test getArcUnits(crv) == "radians" + + setArcCenter!(crv,[1.0,2.0,0.0]) + @test getArcCenter(crv) == [1.0,2.0,0.0] + undo() + @test getArcCenter(crv) == center + redo() + @test getArcCenter(crv) == [1.0,2.0,0.0] + end @testset "Spline Tests" begin @@ -115,5 +192,11 @@ include("../HQMTool.jl") gPts = getSplinePoints(crv) @test isapprox(data,gPts) end +# +# Get spline data from a file +# + # fSpline = newSplineCurve("fromFile", "TestData/SplineData.txt") + # fPts = getSplinePoints(fSpline) + # @test isapprox(data,fPts) end From d849404fc2f786395c8bbdf641c6234b4666b78f Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Wed, 23 Mar 2022 18:26:02 -0700 Subject: [PATCH 016/164] Create Model Tests All but remove inner curve tested --- src/Project/ModelAPI.jl | 26 +++++------ src/Test/ModelTests.jl | 98 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 15 deletions(-) create mode 100644 src/Test/ModelTests.jl diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 336f70ae..1d7203b2 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -58,9 +58,7 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) push!(proj.outerBndryNames,crv["name"]) - enableUndo() registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") - enableNotifications() postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -72,7 +70,7 @@ function removeOuterBoundaryCurveWithName!(proj::Project, name::String) lst = getOuterBoundaryChainList(proj) indx = getChainIndex(lst,name) if indx > 0 - removeOuterBoundaryCurveAtIndex(proj,indx) # posts undo/notification + removeOuterBoundaryCurveAtIndex!(proj,indx) # posts undo/notification proj.backgroundGridShouldUpdate = true end end @@ -98,25 +96,25 @@ function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, insert!(proj.outerBndryPoints,indx,curvePoints(crv,defaultPlotPts)) insert!(proj.outerBndryNames,indx,crv["name"]) proj.backgroundGridShouldUpdate = true + registerWithUndoManager(proj,removeOuterBoundaryCurveAtIndex!,(indx,),"Add Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end -function removeOuterBoundaryCurveAtIndex(proj::Project, indx::Int) +function removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) lst = getOuterBoundaryChainList(proj) crv = lst[indx] deleteat!(lst,indx) deleteat!(proj.outerBndryNames,indx) deleteat!(proj.outerBndryPoints,indx) proj.backgroundGridShouldUpdate = true - enableNotifications() - enableUndo() registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Add Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ - addOuterBoundary!(proj::Project) + addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) Add an empty outer boundary to the project. There can be only one. +This function is only used as part of an undo operation removing the outer boundary """ function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) model = getModelDict(proj) @@ -132,26 +130,24 @@ function removeOuterboundary!(proj::Project) modelDict = getModelDict(proj) if haskey(modelDict,"OUTER_BOUNDARY") ob = modelDict["OUTER_BOUNDARY"] - enableUndo() registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") delete!(modelDict,"OUTER_BOUNDARY") proj.outerBndryPoints = Any[] proj.outerBndryNames = String[] proj.backgroundGridShouldUpdate = true - enableNotifications() postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end end -function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) - modelDict = getModelDict(proj) - modelDict["OUTER_BOUNDARY"] = obDict -end +# function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) +# modelDict = getModelDict(proj) +# modelDict["OUTER_BOUNDARY"] = obDict +# end # # -------------------------------------------------------------------------------------- # """ - getOuterBoundary(proj::Project) + getOuterBoundaryChainList(proj::Project) Get the array of outer boundary curves. """ @@ -216,7 +212,7 @@ end """ removeInnerBoundaryCurve!(proj::Project, name::String) -Remove the named curve in the outer boundary +Remove the named curve in the inner boundary """ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) i, chain = getInnerBoundaryChainWithName(proj,chainName) diff --git a/src/Test/ModelTests.jl b/src/Test/ModelTests.jl new file mode 100644 index 00000000..fafd723c --- /dev/null +++ b/src/Test/ModelTests.jl @@ -0,0 +1,98 @@ +using Test +include("../HQMTool.jl") +#= + Model Tests tests the "ModelAPI.jl" functions + +Functions: @ = tested + @@ = indirectly tested through other tests + + @ addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + @@ removeOuterBoundaryCurveWithName!(proj::Project, name::String) + @ getOuterBoundaryCurveWithName(proj::Project, name::String) + @@ insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) + @@ removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) + @@ addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) + @ removeOuterboundary!(proj::Project) + @ getOuterBoundaryChainList(proj::Project) + + @@ addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + @ removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + @@ insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, + indx::Int, boundaryName::String) + @@ removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) + removeInnerBoundary!(proj::Project, chainName::String) + @@ addInnerBoundaryWithName!(proj::Project,name::String) + @ getChainIndex(chain::Vector{Dict{String, Any}},name) + @@ getAllInnerBoundaries(proj::Project) + @ getInnerBoundaryChainWithName(proj::Project, name::String) + @ getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + innerBoundaryIndices(proj::Project, curveName::String) + + @ getModelDict(proj::Project) + @@ getDictInModelDictNamed(proj::Project,name::String) +=# +@testset "Model Tests" begin +# +# Project for the model +# + projectName = "TestProject" + projectPath = "./Test/TestData" + + p = newProject(projectName, projectPath) +# +# Create some boundary curves +# + obc1 = new("obc1",[0.0,0.0,0.0], [2.0,0.0,0.0]) + obc2 = new("obc2",[2.0,0.0,0.0], [1.0,1.0,0.0]) + obc3 = new("obc3",[1.0,1.0,0.0], [0.0,0.0,0.0]) +# + add!(p,obc1) + add!(p,obc2) + addCurveToOuterBoundary!(p,obc3) + + obList = getOuterBoundaryChainList(p) + @test length(obList) == 3 + @test getChainIndex(obList,"obc3") == 3 + @test undoActionName() == "Add Curve" + undo() + @test length(obList) == 2 + redo() + @test length(obList) == 3 + + crv = getOuterBoundaryCurveWithName(p,"obc2") + @test getCurveName(crv) == "obc2" +# +# Test remove/add outer boundary +# + removeOuterboundary!(p) + mDict = getModelDict(p) + @test haskey(mDict,"OUTER_BOUNDARY") == false + undo() + @test haskey(mDict,"OUTER_BOUNDARY") == true + crv = getOuterBoundaryCurveWithName(p,"obc2") + @test getCurveName(crv) == "obc2" + redo() + @test haskey(mDict,"OUTER_BOUNDARY") == false +# +# Inner boundary curve tests +# + ib1Name = "Inner1" + add!(p,obc1,ib1Name) + add!(p,obc2,ib1Name) + add!(p,obc3,ib1Name) + + i, chain = getInnerBoundaryChainWithName(p,ib1Name) + ibList = chain["LIST"] + @test length(ibList) == 3 + + ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) + @test getCurveName(ibc) == "obc2" + + removeInnerBoundaryCurve!(p,"obc2",ib1Name) + @test length(ibList) == 2 + undo() + @test length(ibList) == 3 + ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) + @test getCurveName(ibc) == "obc2" + +end \ No newline at end of file From a7a8442753cee8d45056d74f2ec2bd7793f3ce03 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Wed, 23 Mar 2022 18:28:38 -0700 Subject: [PATCH 017/164] Update Tests.jl Update to add model tests to main test file. --- src/Test/Tests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl index 2c529195..4cdac694 100644 --- a/src/Test/Tests.jl +++ b/src/Test/Tests.jl @@ -35,3 +35,4 @@ include("ProjectTests.jl") include("SmootherTests.jl") include("RunParametersTests.jl") include("RefinementTests.jl") +include("ModelTests.jl") From fdc632be09bb83892f6ad208621efbc28a4f959e Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Thu, 24 Mar 2022 08:44:23 -0700 Subject: [PATCH 018/164] Project Tests Do tests on project, except for notification actions. --- src/Test/ProjectTests.jl | 43 +++++++++++++++++++++++++++++----- src/Test/RunParametersTests.jl | 6 ++--- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/src/Test/ProjectTests.jl b/src/Test/ProjectTests.jl index eed6f35c..7abd11bd 100644 --- a/src/Test/ProjectTests.jl +++ b/src/Test/ProjectTests.jl @@ -1,8 +1,27 @@ using Test include("../HQMTool.jl") -# -# Project Tests tests the "Project.jl" functions -# +#= + Project Tests tests the "Project.jl" functions + +Functions: @ = tested + + @ openProject(fileName::String, folder::String) + @ saveProject(proj::Project) + @ newProject(name::String, folder::String) + @ hasBackgroundGrid(proj::Project) + @@ assemblePlotArrays(proj::Project) + @ projectBounds(proj::Project) + @ projectGrid(proj::Project) + + curveDidChange(proj::Project,crv::Dict{String,Any}) + modelDidChange(proj::Project, sender::Project) + backgroundGridDidChange(proj::Project, sender::Project) + refinementWasAdded(proj::Project, sender::Project) + refinementDidChange(proj::Project, sender::Dict{String,Any}) + meshWasGenerated(proj::Project, sender::Project) + meshWasDeleted(proj::Project, sender::Project) + +=# @testset "Project Tests" begin # # Create, save, and read @@ -26,10 +45,22 @@ include("../HQMTool.jl") cDict = getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == false + p = openProject("AllFeatures.control",projectPath) + @test hasBackgroundGrid(p) == true + bounds = [25.28, -20.0, -5.0, 20.0] + @test isapprox(p.bounds,bounds) + refinementNames = ["center", "line"] + @test p.refinementRegionNames == refinementNames + @test isapprox(p.refinementRegionLoc[1],[9.0,-3.0]) - # p = openProject("AllFeatures.control",projectPath) - - # @test hasBackgroundGrid(p) == true + obNames = ["B1", "B2", "B3"] + @test p.outerBndryNames == obNames + xGrid = [-23.0, -20.0, -17.0, -14.0, -11.0, -8.0, -5.0, -2.0, 1.0, 4.0, 7.0, + 10.0, 13.0, 16.0, 19.0, 22.0] + yGrid = [-8.0, -5.0, -2.0, 1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0, 22.0, 25.0, 28.0] + p.xGrid, p.yGrid = projectGrid(p) + @test isapprox(p.xGrid,xGrid) + @test isapprox(p.yGrid,yGrid) end diff --git a/src/Test/RunParametersTests.jl b/src/Test/RunParametersTests.jl index 362d9a36..ebeb1198 100644 --- a/src/Test/RunParametersTests.jl +++ b/src/Test/RunParametersTests.jl @@ -5,9 +5,9 @@ include("../HQMTool.jl") Functions: @ = tested @ addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", - polynomialOrder::Int = 5) + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) @ removeRunParameters!(proj::Project) @ setName!(proj::Project,name::String) @ getName(proj::Project) From 1ad7a7b4c75ac56022176d72b23d0d60e6a67b17 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Thu, 24 Mar 2022 08:48:26 -0700 Subject: [PATCH 019/164] Update Tests.jl Add project tests to suite --- src/Test/Tests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl index 4cdac694..c681d057 100644 --- a/src/Test/Tests.jl +++ b/src/Test/Tests.jl @@ -36,3 +36,4 @@ include("SmootherTests.jl") include("RunParametersTests.jl") include("RefinementTests.jl") include("ModelTests.jl") +include("ProjectTests.jl") From 8b2cd901ee8359122a29936fc422b2087cd51187 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:15:20 +0100 Subject: [PATCH 020/164] fix image rendering in HQMTool docs --- docs/src/HQMTool.md | 138 ++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index da42ac40..f04de3fe 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -24,7 +24,7 @@ HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. ## Introduction -HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. +HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run runDemo() @@ -85,7 +85,7 @@ To develop the model, one adds curves to the outer boundary or to multiple inner - Lines defined by their end points - Circular arcs -In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. +In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. @@ -98,9 +98,9 @@ One run parameter that must be set manually is the background grid. Since there The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. The script finishes by generating the quad mesh and plotting the results, as shown below -```@raw html -iceCreamCone -``` + +![iceCreamCone](https://user-images.githubusercontent.com/3637659/132798939-218a3379-7d50-4f3e-9bec-e75e6cd79031.png) + It also returns the project so that it can be edited further, if desired. @@ -119,15 +119,15 @@ To create generate a mesh you - [Create a project](#newProject) p = newProject(,) - + - [Create inner and outer boundary curves](#DefiningCurves) - + c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) c = new(, xEqn, yEqn, zEqn ) (Parametric equation) c = new(, dataFile) (Spline) c = new(, nKnots, knotsMatrix) (also Spline) - + - [Add curves](#AddingCurves) to build the model to see what you have added, add!(p, ) (Add outer boundary curve) @@ -136,11 +136,11 @@ To create generate a mesh you - To [visualize](#Plotting) the project's model, plotProject(p,MODEL) - + To update the plot at any time, use - + updatePlot!(p, options) - + Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) - Set the [background grid](#(#BackgroundGrid)) @@ -148,17 +148,17 @@ To create generate a mesh you addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) *OR* addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) - + addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) - [Adjust parameters](#RunParameters), if desired (e.g.) setPolynomialOrder!(p,order) - + - Generate the mesh generateMesh(p) - + The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. @@ -169,11 +169,11 @@ The mesh will be stored in `` with the name `.mesh`. The co #### New Project (Return:Project) proj = newProject(name::String, folder::String) - + The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). - + #### Opening an existing project file - + (Return:Project) proj = openProject(fileName::String, folder::String) @@ -206,7 +206,7 @@ The project name is the name under which the mesh, plot, statistics and control setName!(proj::Project,name::String) - + #### Getting the current name of a Project [Return:String] getName(proj::Project) @@ -216,7 +216,7 @@ The project name is the name under which the mesh, plot, statistics and control #### Editing the Run Parameters The run parameters can be enquired and set with these getter/setter pairs: - + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) [Return:Int] getPolynomialOrder(proj::Project) [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) @@ -229,7 +229,7 @@ The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be vi #### Changing the output file names By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with - + [Return:nothing] setName!(proj::Project,name::String) [Return:String] getName(proj::Project) [Return:nothing] setFolder!(proj::Project,folder::String) @@ -238,7 +238,7 @@ By default, the mesh, plot and stats files will be written with the name and pat #### Adding the background grid There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. - + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) @@ -247,10 +247,10 @@ Use one of the first two if there is no outer boundary. With the first, a rectan #### Smoothing Operations -A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. - +A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. + To change the defaults, the smoother parameters can be set/enquired with the functions - + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) [Return:String] getSmoothingStatus(proj::Project) [Return:nothing] setSmoothingType!(proj::Project, type::String) @@ -258,49 +258,49 @@ To change the defaults, the smoother parameters can be set/enquired with the fun [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) [Return:Int] getSmoothingIterations(proj::Project) -`status` is either "ON" or "OFF". +`status` is either "ON" or "OFF". To remove the smoother altogether, - + [Return:nothing] removeSpringSmoother!(proj::Project) #### Manual Refinement Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. - + To create a refinement center, - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, x0::Array{Float64}, h::Float64, w::Float64 ) - + where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. - + Similarly, one can create a `RefinementLine`, - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, x0::Array{Float64}, x1::Array{Float64}, h::Float64, w::Float64 ) where `x0` is the start postition and `x1` is the end of the line. - + To add a refinement region to the project, [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) - -To get the indx'th refinement region from the project, or to get - a refinement region with a given name, use + +To get the indx'th refinement region from the project, or to get + a refinement region with a given name, use [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) - -Finally, to get a list of all the refinement regions, - + +Finally, to get a list of all the refinement regions, + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) - + A refinement region can be edited by using the following - + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) [Return:String] getRefinementType(r::Dict{String,Any}) [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) @@ -309,16 +309,16 @@ A refinement region can be edited by using the following [Return:float64] getRefinementGridSize(r::Dict{String,Any}) [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) [Return:float64] getRefinementWidth(r::Dict{String,Any}) - + where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. - + To further edit a `RefinementLine`, use the methods - + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) - + ### Boundary Curves #### Adding and Removing Outer and Inner Boundaries @@ -335,7 +335,7 @@ To further edit a `RefinementLine`, use the methods Example: add!(p,circ) - + - Adding an inner boundary curve [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @@ -371,29 +371,29 @@ Four curve types can be added to the outer and inner boundary curve chains. They ##### Parametric Equations -- Creating new +- Creating new - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) Generic: new(...) - - Returns a new parametric equation. Equations must be of the form - + + Returns a new parametric equation. Equations must be of the form + () = ... - + The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. - + Example: - + x(s) = 2.0 + 3*cos(2*pi*s)^2 - + The z-Equation is optional, but for now must define zero for z. - + ##### Line Defined by End Points - [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, xStart::Array{Float64}, xEnd::Array{Float64}) Generic: new(...) @@ -405,20 +405,20 @@ Example: cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) ##### Circular Arc - [Return:Dict{String,Any}] newCircularArcCurve(name::String, - center::Array{Float64}, + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String) Generic: new(...) The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". - -Example: + +Example: iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - + ##### Spline Curve A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. @@ -445,11 +445,11 @@ If the curve is to be closed. The last point must be the same as the first. #### Editing Curves -You can determine the type of a curve by +You can determine the type of a curve by [Return:String] getCurveType(crv::Dict{String,Any}) - -For any of the curves, their name can be changed by + +For any of the curves, their name can be changed by setCurveName!(crv::Dict{String,Any}, name::String) @@ -469,7 +469,7 @@ Otherwise there are special functions to change the parameters of curves [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) - + [Return:String] getXEqn(crv::Dict{String,Any}) [Return:String] getYEqn(crv::Dict{String,Any}) [Return:String] getZEqn(crv::Dict{String,Any}) @@ -489,7 +489,7 @@ In interactive mode, actions can be undone by the commands [Return:String] undo() [Return:String] redo() - + where the return string contains the name of the action performed. To find out what the next actions are, use From b329830aa7e446880d9a5c56e125c1c0544d9d01 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:22:03 +0100 Subject: [PATCH 021/164] update the docs for the new plotting capabilities --- docs/src/HQMTool.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index f04de3fe..7ba519bb 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -91,7 +91,7 @@ Similarly, you create curves and add them to as many inner boundaries that you w For convenience, `newProject` will generate default run parameters, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). -One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extend of the domain to be meshed, so only the mesh size needs to be specified using +One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extent of the domain to be meshed, so only the mesh size needs to be specified using addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) @@ -101,7 +101,6 @@ The script finishes by generating the quad mesh and plotting the results, as sho ![iceCreamCone](https://user-images.githubusercontent.com/3637659/132798939-218a3379-7d50-4f3e-9bec-e75e6cd79031.png) - It also returns the project so that it can be edited further, if desired. To save a control file for HOHQMesh, simply invoke @@ -224,7 +223,7 @@ The run parameters can be enquired and set with these getter/setter pairs: [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) [Return:String] getPlotFileFormat(proj::Project) -The mesh file format is either `ISM` or `ISM-V2`. The plot file (Which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite elemnt represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** +The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. #### Changing the output file names @@ -233,7 +232,7 @@ By default, the mesh, plot and stats files will be written with the name and pat [Return:nothing] setName!(proj::Project,name::String) [Return:String] getName(proj::Project) [Return:nothing] setFolder!(proj::Project,folder::String) - [Return:String] getFolder(proj::Project) + [Return:String] getFolder(proj::Project) #### Adding the background grid @@ -503,4 +502,4 @@ Finally, to clear the undo stack, use ## Advanced -All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. +All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file From 1aff854c76d70b24f50c14c6da4bae4e5e4cf24d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:31:44 +0100 Subject: [PATCH 022/164] remove doc files in HQMTool folder from the repo --- HQMTool/Doc/CheatSheet.md | 64 ----- HQMTool/Doc/HQMTool.md | 501 ----------------------------------- HQMTool/Doc/iceCreamCone.png | Bin 436345 -> 0 bytes 3 files changed, 565 deletions(-) delete mode 100644 HQMTool/Doc/CheatSheet.md delete mode 100644 HQMTool/Doc/HQMTool.md delete mode 100644 HQMTool/Doc/iceCreamCone.png diff --git a/HQMTool/Doc/CheatSheet.md b/HQMTool/Doc/CheatSheet.md deleted file mode 100644 index 05763e8a..00000000 --- a/HQMTool/Doc/CheatSheet.md +++ /dev/null @@ -1,64 +0,0 @@ -#HQMTool CheatSheet - -Workflow: - -1. Create a project -2. Add boundary curves -4. Add a background grid -3. Add manual refinement (if desired) -5. Generate mesh - -### Project - - p = newProject(,) - -### Plotting - - plotProject!(p,options) - updatePlot!(p,options) - -### Curves - - c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* - c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* - c = new(name, xEqn, yEqn, zEqn ) *Parametric equation* - c = new(name, dataFile) *Spline* - c = new(name, nKnots, knotsMatrix) *also Spline* - -### Manual Refinement - - r = newRefinementCenter(name, center, gridSize, radius ) - r = newRefinementLine(name,type, startPoint, endPoint, gridSize, width ) -### Adding to a Project - - add!(p, c) *Add outer boundary curve* - add!(p, c, ) *add curve to an inner boundary* - add!(p, r) *Add refinement region* - - addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* - addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* - -### Accessing items - - crv = get(p,curveName) *Get a curve in the outer boundary* - crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* - indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* - r = getRefinementRegion(p, name) - -### Removing from Project - - removeOuterboundary!(p) *Entire outer boundary curve* - removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve - remove!(p, name) *Curve in outer boundary* - remove!(p, name, innerBoundaryName) *Curve in inner boundary* - removeRefinementRegion!(p, name) - -### Editing items - -All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. - -### Meshing - - generateMesh(p) - removeMesh!(p) - \ No newline at end of file diff --git a/HQMTool/Doc/HQMTool.md b/HQMTool/Doc/HQMTool.md deleted file mode 100644 index 03793642..00000000 --- a/HQMTool/Doc/HQMTool.md +++ /dev/null @@ -1,501 +0,0 @@ -#HQMTool -HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. - -## Contents - -1. [Introduction](#introduction) -2. [Basic Moves](#basicMoves) -3. [HQMTool API](#API) - 1. [Project Creation and Saving](#Project) - 2. [Plotting](#Plotting) - 3. [Modifying/Editing a Project](#EditingProject) - 4. [Controlling the Mesh Generation Process](#Control) - 1. [Editing the Run Parameters](#RunParameters) - 2. [Changing the output file names](#OutputFiles) - 3. [Adding the background grid](#BackgroundGrid) - 4. [Smoothing Operations](#Smoother) - 5. [Manual Refinement](#ManualRefinement) - 5. [Boundary Curves](#BoundaryCurves) - 1. [Adding and Removing Outer and Inner Boundaries](#AddingCurves) - 2. [Defining Curves](#DefiningCurves) - 3. [Editing Curves](#EditingCurves) - 6. [Undo/Redo](#Undo) -4. [Advanced](#Advanced) - -## Introduction - -HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. -To see that example, run - - runDemo() - -The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The script is - - function iceCreamCone(folder::String) - # - # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `path`. This version uses generic versions of - # the API. - # - p = newProject("IceCreamCone",path) - # - # Outer boundary - # - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) - # - # Inner boundary - # - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) # A line - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") # An arc - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) # A line - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") - # - # Set some control RunParameters to overwrite the defaults - # - setPolynomialOrder!(p,4) - setPlotFileFormat!(p,"sem") - # - # To mesh, a background grid is needed - # - addBackgroundGrid!(p, [0.1,0.1,0.0]) - # - # Show the model and grid - # - plotProject!(p, MODEL+GRID) - # - # Generate the mesh and plot - # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - updatePlot!(p, MODEL+MESH) - - return p - end - -The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. - -To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, if desired. As in HOHQMesh, there are four curve classes currently operational: - -- Parametric equations -- Splines -- Lines defined by their end points -- Circular arcs - -In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. - -Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. - -For convenience, `newProject` will generate default run parameters, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). - -One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extent of the domain to be meshed, so only the mesh size needs to be specified using - - addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) - -The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. - -The script finishes by generating the quad mesh and plotting the results, as shown below -![](iceCreamCone.png) It also returns the project so that it can be edited further, if desired. - -To save a control file for HOHQMesh, simply invoke - - saveProject(proj::Project,outFile::String) - -where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. - -Methods are available to edit a model. For example to move the center of the outer boundary - -## Basic Moves - -To create generate a mesh you - -- [Create a project](#newProject) - - p = newProject(,) - -- [Create inner and outer boundary curves](#DefiningCurves) - - c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) - c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) - c = new(, xEqn, yEqn, zEqn ) (Parametric equation) - c = new(, dataFile) (Spline) - c = new(, nKnots, knotsMatrix) (also Spline) - -- [Add curves](#AddingCurves) to build the model to see what you have added, - - add!(p, ) (Add outer boundary curve) - add!(p, , ) (add curve to an inner boundary) - -- To [visualize](#Plotting) the project's model, - - plotProject(p,MODEL) - - To update the plot at any time, use - - updatePlot!(p, options) - - Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) - -- Set the [background grid](#(#BackgroundGrid)) - - addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) - *OR* - addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) - - addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) - -- [Adjust parameters](#RunParameters), if desired (e.g.) - - setPolynomialOrder!(p,order) - -- Generate the mesh - - generateMesh(p) - -The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. - - -#HQMTool API -# Project Creation and Saving - -### New Project - - (Return:Project) proj = newProject(name::String, folder::String) - -The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). - -### Opening an existing project file - - (Return:Project) proj = openProject(fileName::String, folder::String) - - -### Saving a project - - saveProject(proj::Project) - -writes a control file to the folder designated when creating the new project. It can be read in again with OpenProject. - -# Plotting - -### Plotting a Project - - plotProject(proj::Project, options) - -The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show where [manual refinement](#ManualRefinement) is added. - -If the model is modified and you want to re-plot with the new values, invoke - - updatePlot!(proj::Project, options) - -but genrally the plot will be updated automatically as you build the model. - - -# Modifying/Editing a Project - -### Setting the name of a project - -The project name is the name under which the mesh, plot, statistics and control files will be written. - - setName!(proj::Project,name::String) - - -### Getting the current name of a Project - - [Return:String] getName(proj::Project) - -# Controlling the Mesh Generation Process - -### Editing the Run Parameters - -The run parameters can be enquired and set with these getter/setter pairs: - - [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) - [Return:Int] getPolynomialOrder(proj::Project) - [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) - [Return:String] getMeshFileFormat(proj::Project) - [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) - [Return:String] getPlotFileFormat(proj::Project) - -The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. **At this time, if you want to plot the grid in HQMTool, then you must use `ISM-V2` as the mesh file format.** - -### Changing the output file names - -By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with - - [Return:nothing] setName!(proj::Project,name::String) - [Return:String] getName(proj::Project) - [Return:nothing] setFolder!(proj::Project,folder::String) - [Return:String] getFolder(proj::Project) - -### Adding the background grid - -There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. - - [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) - -Use one of the first two if there is no outer boundary. With the first, a rectangular outer boundary will be created of extent [x0[1], x0[1]+N dx[1]]X[x0[2], x0[2]+N*dx[2]]. The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. The arrays `x0`, `dx`, `N`, `bgSize` are all vectors [ *, \*, \*] giving the x, y, and z components. - -### Smoothing Operations - -A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. - -To change the defaults, the smoother parameters can be set/enquired with the functions - - [Return:nothing] setSmoothingStatus!(proj::Project, status::String) - [Return:String] getSmoothingStatus(proj::Project) - [Return:nothing] setSmoothingType!(proj::Project, type::String) - [Return:String] getSmoothingType(proj::Project) - [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) - [Return:Int] getSmoothingIterations(proj::Project) - -`status` is either "ON" or "OFF". - -To remove the smoother altogether, - - [Return:nothing] removeSpringSmoother!(proj::Project) - -### Manual Refinement - -Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. - -To create a refinement center, - - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, - x0::Array{Float64}, h::Float64, - w::Float64 ) - -where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. - -Similarly, one can create a `RefinementLine`, - - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, - x0::Array{Float64}, x1::Array{Float64}, - h::Float64, - w::Float64 ) - -where `x0` is the start postition and `x1` is the end of the line. - -To add a refinement region to the project, - - [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) - -To get the indx'th refinement region from the project, or to get - a refinement region with a given name, use - - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) - -Finally, to get a list of all the refinement regions, - - [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) - -A refinement region can be edited by using the following - - [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) - [Return:String] getRefinementType(r::Dict{String,Any}) - [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) - [Return:nothing] setRefinementGridSize!(r::Dict{String,Any},h::Float64) - [Return:float64] getRefinementGridSize(r::Dict{String,Any}) - [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) - [Return:float64] getRefinementWidth(r::Dict{String,Any}) - -where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. - -To further edit a `RefinementLine`, use the methods - - [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) - [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) - -# Boundary Curves - -### Adding Outer and Inner Boundaries - -- Adding an outer boundary curve - - Using the curve creation routines, described in the next section below, create curves in sucessive order counter-clockwise along the outer boundary and add them to the outer boundary curve using - - [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - Generic: add!(...) - - `crv` is the dictionary that represents the curve. - -Example: - - add!(p,circ) - -- Adding an inner boundary curve - - [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - Generic: add!(...) - -Example: - - add!(p,cone1,"IceCreamCone") - -To edit curves they can be accessed by name: - - [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - Generic: get(...) - [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) - Generic: get(...) - -- Deleting boundary curves - - [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) - Generic: remove!(...) - [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - Generic: remove!(...) - -## Defining Curves - -Four curve types can be added to the outer and inner boundary curve chains. They are - -- parametricEquation -- endPointsLine -- circularArc -- spline - - -### Parametric Equations - -- Creating new - - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - Generic: new(...) - - Returns a new parametric equation. Equations must be of the form - - () = ... - - The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. - - Example: - - x(s) = 2.0 + 3*cos(2*pi*s)^2 - - The z-Equation is optional, but for now must define zero for z. - -### Line Defined by End Points - - [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - Generic: new(...) - -The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should be zero and for now is ignored. - -Example: - - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) -### Circular Arc - - [Return:Dict{String,Any}] newCircularArcCurve(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String) - Generic: new(...) - - The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". - -Example: - - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - -### Spline Curve - -A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. - - 9 - 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 - 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 - 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 - 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 - 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 - 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 - 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 - 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 - 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 - -or by constructing the Nx4 array supplying it to the new procedure. The constructors are - - [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) - Generic: new(...) - [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) - Generic: new(...) - -If the curve is to be closed. The last point must be the same as the first. - -## Editing Curves - -You can determine the type of a curve by - - [Return:String] getCurveType(crv::Dict{String,Any}) - -For any of the curves, their name can be changed by - - setCurveName!(crv::Dict{String,Any}, name::String) - -and checked by - - getCurveName(crv::Dict{String,Any}) - -Otherwise there are special functions to change the parameters of curves - - [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) - [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) - - [Return:String] getXEqn(crv::Dict{String,Any}) - [Return:String] getYEqn(crv::Dict{String,Any}) - [Return:String] getZEqn(crv::Dict{String,Any}) - [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) - [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) - [Return:String] getArcUnits(arc::Dict{String,Any}) - [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) - [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) - [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) - [Return:Float64] getArcRadius(arc::Dict{String,Any}) - -## Undo/Redo - -The HQMTool has unlimited undo/redo for most actions. - -In interactive mode, actions can be undone by the commands - - [Return:String] undo() - [Return:String] redo() - -where the return string contains the name of the action performed. - -To find out what the next actions are, use - - [Return:String] undoName() - [Return:String] redoName() - -Finally, to clear the undo stack, use - - [Return:nothing] clearUndoRedo() - -# Advanced - -All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file diff --git a/HQMTool/Doc/iceCreamCone.png b/HQMTool/Doc/iceCreamCone.png deleted file mode 100644 index 23511d2bc9342e0490b3c8cc01e6e67019f3b48f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 436345 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

(R3ztIK~x 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üq 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%0Dr(21&z%>XKL|t4bbV$aAGv@ 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�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 MlK#c)3%CCMFNR>_Y5)KL From c2e0382cde9e7c78cc6219655a14878d23537f3d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:34:37 +0100 Subject: [PATCH 023/164] remove duplicate HQMTool.jl from repo --- HQMTool/HQMTool.jl | 145 --------------------------------------------- 1 file changed, 145 deletions(-) delete mode 100644 HQMTool/HQMTool.jl diff --git a/HQMTool/HQMTool.jl b/HQMTool/HQMTool.jl deleted file mode 100644 index a9b2dd89..00000000 --- a/HQMTool/HQMTool.jl +++ /dev/null @@ -1,145 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -using Base: CyclePadding, Int64, Float64, current_logger, parseint_preamble, String, Bool -using Printf -using HOHQMesh -#= - A program for reading, writing and plotting a model for HOHQMesh -=# -include("Source/Viz/VizMesh.jl") -include("Source/Misc/NotificationCenter.jl") -include("Source/Misc/DictionaryOperations.jl") -include("Source/Curves/Spline.jl") -include("Source/ControlFile/ControlFileOperations.jl") -include("Source/Curves/CurveOperations.jl") -include("Source/Project/Project.jl") -include("Source/Project/CurvesAPI.jl") -include("Source/Viz/VizProject.jl") -include("Source/Project/Undo.jl") -include("Source/Mesh/Meshing.jl") -include("Source/Project/Generics.jl") - -# -#---------------- FOR TESTING PURPOSES -------------------------------------- -# - -function runDemo() -#= - Reads in an existing control file, plots the boundary curves and generates - a mesh. -=# - p = openProject("AllFeatures.control", "Demo") - plotProject!(p,MODEL+REFINEMENTS+GRID) - println("Hit any key to continue and generate the mesh") - readline() - generateMesh(p) - return p -end - -function iceCreamConeVerbose(folder::String) -# -# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# written to `folder`. -# - p = newProject("IceCreamCone",folder) -# -# Outer boundary -# - circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - addCurveToOuterBoundary!(p,circ) -# -# Inner boundary -# - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p,cone1,"IceCreamCone") - addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") - addCurveToInnerBoundary!(p,cone2,"IceCreamCone") -# -# Set some control RunParameters to overwrite the defaults -# - setPolynomialOrder!(p,4) - setPlotFileFormat!(p,"sem") -# -# To mesh, a background grid is needed -# - addBackgroundGrid!(p, [0.5,0.5,0.0]) -# -# Show the model and grid -# - plotProject!(p, MODEL+GRID) -# -# Generate the mesh and plot -# - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - - return p -end - -function iceCreamCone(folder::String) - # - # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `path`. - # - p = newProject("IceCreamCone",folder) - # - # Outer boundary - # - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) - # - # Inner boundary - # - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") - # - # To mesh, a background grid is needed - # - addBackgroundGrid!(p, [0.5,0.5,0.0]) - setMeshFileFormat!(p, "ABAQUS") - meshFileFormat = getMeshFileFormat(p) - setFileNames!(p, meshFileFormat) - # - # Show the model and grid - # - plotProject!(p, MODEL+GRID) - # - # Generate the mesh and plot - # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - - return p -end From 635b2cec4d01afb400984d6c2d099eab62d2aca4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:47:21 +0100 Subject: [PATCH 024/164] give capability to set ABAQUS format and remove duplicate RunParametersAPI --- HQMTool/Source/Project/RunParametersAPI.jl | 194 --------------------- src/Project/RunParametersAPI.jl | 70 ++++---- 2 files changed, 37 insertions(+), 227 deletions(-) delete mode 100644 HQMTool/Source/Project/RunParametersAPI.jl diff --git a/HQMTool/Source/Project/RunParametersAPI.jl b/HQMTool/Source/Project/RunParametersAPI.jl deleted file mode 100644 index 41f89f89..00000000 --- a/HQMTool/Source/Project/RunParametersAPI.jl +++ /dev/null @@ -1,194 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -""" - addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", - polynomialOrder::Int = 5) - -Add a RUN_PARAMETERS block and set all the parameters in one call. -""" -function addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", - polynomialOrder::Int = 5) - - setFileNames!(proj, meshFileFormat) - setPlotFileFormat!(proj,plotFormat) - setMeshFileFormat!(proj,meshFileFormat) - setPolynomialOrder!(proj,polynomialOrder) - - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - registerWithUndoManager(proj,removeRunParameters!, (nothing,), "Add Run Parameters") - - return rpDict -end -""" - removeRunParameters!(proj::Project) - -Remove the run parameters block from the project. -""" -function removeRunParameters!(proj::Project) - cDict = getControlDict(proj) - if haskey(cDict,"RUN_PARAMETERS") - delete!(cDict,"RUN_PARAMETERS") - end -end - -""" - setName(proj::Project,name::String) - -The `name` of the project is the filename to be used by the mesh, plot, and -stats files. It is also the name of the control file the tool will produce. -""" -function setName!(proj::Project,name::String) - - oldName = proj.name - registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") - proj.name = name - setFileNames!(proj, getMeshFileFormat(proj)) -end -""" - getName(proj::Project) - -Returns the filename to be used by the mesh, plot, control, and -stats files. -""" -function getName(proj::Project) - return proj.name -end -""" -setFolder(proj::Project,folder::String) - -Set the path to the directory where the mesh, plot, control, and stats files -will be written -""" -function setFolder(proj::Project,folder::String) - oldPath = proj.path - registerWithUndoManager(proj,setFolder,(oldPath,),"Set Project Folder") - proj.path = folder -end -""" - path(proj::Project) - -Returns the directory where the project files will be written -""" -function getfolder(proj::Project) - return proj.path -end -""" - setPolynomialOrder(proj::Project, p::Int) - -Set the polynomial order for boundary curves in the mesh file to `p`. -""" -function setPolynomialOrder!(proj::Project, p::Int) - key = "polynomial order" - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - if haskey(rpDict,key) - oldP = parse(Int,rpDict[key]) - registerWithUndoManager(proj,setPolynomialOrder!,(oldP,),"Set Order") - end - rpDict["polynomial order"] = string(p) -end -""" - getPolynomialOrder(proj::Project) - -Returns the polynomial order for boundary curves in the mesh file. -""" -function getPolynomialOrder(proj::Project) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return rpDict["polynomial order"] -end -""" - setMeshFileFormat(proj::Project, meshFileFormat::String) - -Set the file format for the mesh file. Acceptable choices -are "ISM", "ISM-V2" and "ABAQUS". -""" -function setMeshFileFormat!(proj::Project, meshFileFormat::String) - if !in(meshFileFormat,meshFileFormats) - println("Acceptable file formats are ISM, ISM-V2, or ABAQUS. Try again.") - return - end - key = "mesh file format" - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - if haskey(rpDict,key) - oldFormat = rpDict[key] - registerWithUndoManager(proj,setMeshFileFormat!,(oldFormat,),"Set Mesh Format") - end - rpDict[key] = meshFileFormat -end -""" - getMeshFileFormat(proj::Project) - -Returns the format in which the mesh will be written. -""" -function getMeshFileFormat(proj::Project) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return rpDict["mesh file format"] -end -""" - setPlotFileFormat(proj::Project, plotFileFormat::String) - -Set the file format for the plot file. Acceptable choices -are "sem", which includes interior nodes and boundary nodes and "skeleton", which includes -only the corner nodes. -""" -function setPlotFileFormat!(proj::Project, plotFileFormat::String) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - key = "plot file format" - if haskey(rpDict,key) - oldFormat = rpDict[key] - registerWithUndoManager(proj,setPlotFileFormat!,(oldFormat,),"Set Plot Format") - end - rpDict[key] = plotFileFormat -end -""" - getPlotFileFormat(proj::Project) - -Returns the plot file format. -""" -function getPlotFileFormat(proj::Project) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return rpDict["plot file format"] -end - -function setFileNames!(proj::Project, meshFileFormat::String) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - if meshFileFormat == "ABAQUS" - rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".inp") - else - rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") - end - rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") - rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") - end - - function getMeshFileName(proj::Project) - rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return rpDict["mesh file name"] - end diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index 23c7fc75..a233e863 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -3,44 +3,44 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# """ - addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", + addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) Add a RUN_PARAMETERS block and set all the parameters in one call. """ -function addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", +function addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) - setFileNames!(proj) - setPlotFileFormat!(proj,plotFormat) - setMeshFileFormat!(proj,meshFileFormat) - setPolynomialOrder!(proj,polynomialOrder) + setFileNames!(proj, meshFileFormat) + setPlotFileFormat!(proj, plotFormat) + setMeshFileFormat!(proj, meshFileFormat) + setPolynomialOrder!(proj, polynomialOrder) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") registerWithUndoManager(proj,removeRunParameters!, (nothing,), "Add Run Parameters") @@ -62,7 +62,7 @@ end """ setName(proj::Project,name::String) -The `name` of the project is the filename to be used by the mesh, plot, and +The `name` of the project is the filename to be used by the mesh, plot, and stats files. It is also the name of the control file the tool will produce. """ function setName!(proj::Project,name::String) @@ -70,17 +70,17 @@ function setName!(proj::Project,name::String) oldName = proj.name registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") proj.name = name - setFileNames!(proj) + setFileNames!(proj, getMeshFileFormat(proj)) end """ getName(proj::Project) -Returns the filename to be used by the mesh, plot, control, and +Returns the filename to be used by the mesh, plot, control, and stats files. """ function getName(proj::Project) return proj.name -end +end """ setPolynomialOrder(proj::Project, p::Int) @@ -102,7 +102,7 @@ Returns the polynomial order for boundary curves in the mesh file. """ function getPolynomialOrder(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - return parse(Int,rpDict["polynomial order"]) + return parse(Int,rpDict["polynomial order"]) end """ setMeshFileFormat(proj::Project, meshFileFormat::String) @@ -162,11 +162,15 @@ function getPlotFileFormat(proj::Project) return rpDict["plot file format"] end -function setFileNames!(proj::Project) +function setFileNames!(proj::Project, meshFileFormat::String) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") - rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") - rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") - rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") + if meshFileFormat == "ABAQUS" + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".inp") + else + rpDict["mesh file name"] = joinpath(proj.projectDirectory, proj.name *".mesh") + end + rpDict["plot file name"] = joinpath(proj.projectDirectory, proj.name *".tec") + rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") end function getMeshFileName(proj::Project) @@ -178,7 +182,7 @@ function setFileNames!(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["plot file name"] end - + function getStatsFileName(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["stats file name"] From 86a836f7851cd9d8543583dfe05ab2e1f0f60aad Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:54:01 +0100 Subject: [PATCH 025/164] add capability to plot all three mesh file formats --- src/Viz/VizMesh.jl | 235 +++++++++++++++++++++++++++++++++++------- src/Viz/VizProject.jl | 45 ++++---- 2 files changed, 219 insertions(+), 61 deletions(-) diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index 452e9f2c..ac8bbb69 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -3,61 +3,220 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# -function getMeshFromMeshFile(meshFile::AbstractString) +function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) + + if meshFileFormat == "ISM-V2" + open(meshFile,"r") do f + line = strip(readline(f)) # Header Should be ISM-V2 + line = readline(f) # Numbers of nodes, edges ... + values = split(line) + + nNodes = parse(Int,values[1]) + nEdges = parse(Int,values[2]) +# +# Read the nodes +# + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64,values[j]) + end + end +# +# Read the edges and construct the lines array +# + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) - open(meshFile,"r") do f - line = strip(readline(f)) #Header Should be ISM-V2 - if line != "ISM-V2" - error("Mesh file must be ISM-V2") - return nothing + for i = 1:3:3*nEdges + + values = split(readline(f)) + n = parse(Int,values[1]) + m = parse(Int,values[2]) + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN + + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + + end + return xMesh, yMesh end - line = readline(f) # Numbers of nodes, edges ... - values = split(line) + elseif meshFileFormat == "ISM" + open(meshFile,"r") do f + # There is no header + line = readline(f) # Numbers of corners, elements and boundary polynomial order + values = split(line) + + nNodes = parse(Int,values[1]) + nElements = parse(Int,values[2]) + nBndy = parse(Int, values[3]) +# +# Read the nodes +# + nodes = zeros(Float64,nNodes,2) + for i = 1:nNodes + values = split(readline(f)) + for j = 1:2 + nodes[i,j] = parse(Float64, values[j]) + end + end +# +# Read the element ids (and skip all the boundary information) +# + elements = zeros(Int64,nElements,4) + temp = zeros(Int64, 4) + for i = 1:nElements + values = split(readline(f)) + for j = 1:4 + elements[i,j] = parse(Int64, values[j]) + end + values = split(readline(f)) + for j = 1:4 + temp[j] = parse(Int64, values[j]) + end + if sum(temp) == 0 + # straight-sided edge so just skip the boundary labels + readline(f) + else + # curved edge so skip the boundary polynomial and the labels + for i = 1:nBndy+1 + readline(f) + end + readline(f) + end + end + # convenience mapping for element index corners + p = [[1 2 4 1] + [2 3 3 4]] + # Build the edges. This is only for plotting purposes so we might have some + # repeated edges + edge_id = 0 + #hash_table = Dict{Int, Int}() + edges = Dict{Int, Any}() + for j in 1:nElements + for k in 1:4 + id1 = elements[j , p[1,k]] + id2 = elements[j , p[2,k]] + key_val = id1 + id2 + edge_id += 1 + #push!( hash_table , key_val => edge_id ) + push!( edges , edge_id => [id1 id2] ) + end # k + end # j + # set the total number of edges + nEdges = edge_id + # use the edge information and pull the corner node physical values + xMesh = zeros(Float64,3*nEdges) + yMesh = zeros(Float64,3*nEdges) + edge_id = 0 + for i = 1:3:3*nEdges + edge_id += 1 + current_edge = edges[edge_id] + n = current_edge[1] + m = current_edge[2] + + xMesh[i] = nodes[n,1] + xMesh[i+1] = nodes[m,1] + xMesh[i+2] = NaN - nNodes = parse(Int,values[1]) - nEdges = parse(Int,values[2]) + yMesh[i] = nodes[n,2] + yMesh[i+1] = nodes[m,2] + yMesh[i+2] = NaN + end + return xMesh, yMesh + end + elseif meshFileFormat == "ABAQUS" + # read in the entire file + file_lines = readlines(open(meshFile)) + # obtain the number of corners and elements in a circuitous way due to the ABAQUS format + # number of corner nodes + file_idx = findfirst(contains("*ELEMENT"), file_lines) - 1 + current_line = split(file_lines[file_idx], ",") + nNodes = parse(Int, current_line[1]) + # number of elements + file_idx = findfirst(contains("** ***** HOHQMesh boundary information ***** **"), file_lines) - 1 + current_line = split(file_lines[file_idx], ",") + nElements = parse(Int, current_line[1]) # -# Read the nodes +# Read in the nodes # nodes = zeros(Float64,nNodes,2) - for i = 1:nNodes - values = split(readline(f)) - for j = 1:2 - nodes[i,j] = parse(Float64,values[j]) + file_idx = 4 + for i in 1:nNodes + current_line = split(file_lines[file_idx], ",") + for j = 2:3 + nodes[i, j-1] = parse(Float64, current_line[j]) end - end + file_idx += 1 + end # i # -# Read the edges and construct the lines array +# Read the element ids (and skip all the boundary information) # + elements = zeros(Int64,nElements,4) + # eat the element header + file_idx += 1 + for i = 1:nElements + current_line = split(file_lines[file_idx], ",") + for j = 2:5 + elements[i,j-1] = parse(Int64, current_line[j]) + end + file_idx += 1 + end + # convenience mapping for element index corners + p = [[1 2 4 1] + [2 3 3 4]] + # Build the edges. This is only for plotting purposes so we might have some + # repeated edges + edge_id = 0 + #hash_table = Dict{Int, Int}() + edges = Dict{Int, Any}() + for j in 1:nElements + for k in 1:4 + id1 = elements[j , p[1,k]] + id2 = elements[j , p[2,k]] + key_val = id1 + id2 + edge_id += 1 + #push!( hash_table , key_val => edge_id ) + push!( edges , edge_id => [id1 id2] ) + end # k + end # j + # set the total number of edges + nEdges = edge_id + # use the edge information and pull the corner node physical values xMesh = zeros(Float64,3*nEdges) yMesh = zeros(Float64,3*nEdges) - + edge_id = 0 for i = 1:3:3*nEdges - - values = split(readline(f)) - n = parse(Int,values[1]) - m = parse(Int,values[2]) + edge_id += 1 + current_edge = edges[edge_id] + n = current_edge[1] + m = current_edge[2] xMesh[i] = nodes[n,1] xMesh[i+1] = nodes[m,1] @@ -66,11 +225,9 @@ function getMeshFromMeshFile(meshFile::AbstractString) yMesh[i] = nodes[n,2] yMesh[i+1] = nodes[m,2] yMesh[i+2] = NaN - - end + end return xMesh, yMesh - end - + end end function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index 5dc33818..d36099ea 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# using GLMakie @@ -31,10 +31,10 @@ const REFINEMENTS = 8; const ALL = 15 plotProject!(proj::Project, plotOptions::Int = 0) Plot objects specified by the `plotOptions`. Construct the `plotOptions` by the sum -of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. +of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. Example: To plot the model and the grid, `plotOptions = MODEL + GRID`. To plot -just the mesh, `plotOptions = MESH`. +just the mesh, `plotOptions = MESH`. To plot everything, `plotOptions = MODEL + GRID + MESH + REFINEMENTS` @@ -75,7 +75,8 @@ function plotProject!(proj::Project, plotOptions::Int = 0) if proj.meshShouldUpdate || (isempty(proj.xMesh) && isempty(proj.yMesh)) meshFileName = getMeshFileName(proj) if isfile(meshFileName) - proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName) + fileFormat = getMeshFileFormat(proj) + proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName, fileFormat) plotMesh(plt, proj.xMesh, proj.yMesh) end proj.meshShouldUpdate = false @@ -115,10 +116,10 @@ function plotProject!(proj::Project, plotOptions::Int = 0) if plotTheRefinements if !isempty(proj.refinementRegionNames) plotRefinement(plt,proj.refinementRegionPoints, - proj.refinementRegionNames, + proj.refinementRegionNames, proj.refinementRegionLoc) end - end + end # # Display the plot # @@ -140,7 +141,7 @@ end """ updatePlot!(proj::Project, plotOptions::Int) -Replot with the new plotOptions = combinations (sums) of +Replot with the new plotOptions = combinations (sums) of GRID, MESH, MODEL, REFINEMENTS @@ -162,7 +163,7 @@ function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) for i = 2:s x = chainPoints[i] plotCurve(plt,x,labels[i]) - end + end end function plotCurve(plt, points::Matrix{Float64}, label::String) @@ -170,7 +171,7 @@ function plotCurve(plt, points::Matrix{Float64}, label::String) s = size(points) np = div(s[1], 2, RoundNearest) if s[1] == 3 - np = 2 + np = 2 end dx = points[np+1,1] - points[np-1,1] dy = points[np+1,2] - points[np-1,2] @@ -189,5 +190,5 @@ function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String p = loc[i] pp = (p[1],p[2]) text!(plt[1,1],label[i],position = pp, align = (:center,:center)) - end + end end From b9896312d09702ca99425dcb2117978c9dde0e44 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 10:54:38 +0100 Subject: [PATCH 026/164] remove dulplicate Viz files from the HQMTool folder --- HQMTool/Source/Viz/VizMesh.jl | 235 ------------------------------- HQMTool/Source/Viz/VizProject.jl | 195 ------------------------- 2 files changed, 430 deletions(-) delete mode 100644 HQMTool/Source/Viz/VizMesh.jl delete mode 100644 HQMTool/Source/Viz/VizProject.jl diff --git a/HQMTool/Source/Viz/VizMesh.jl b/HQMTool/Source/Viz/VizMesh.jl deleted file mode 100644 index e2d07923..00000000 --- a/HQMTool/Source/Viz/VizMesh.jl +++ /dev/null @@ -1,235 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) - - if meshFileFormat == "ISM-V2" - open(meshFile,"r") do f - line = strip(readline(f)) # Header Should be ISM-V2 - line = readline(f) # Numbers of nodes, edges ... - values = split(line) - - nNodes = parse(Int,values[1]) - nEdges = parse(Int,values[2]) -# -# Read the nodes -# - nodes = zeros(Float64,nNodes,2) - for i = 1:nNodes - values = split(readline(f)) - for j = 1:2 - nodes[i,j] = parse(Float64,values[j]) - end - end -# -# Read the edges and construct the lines array -# - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) - - for i = 1:3:3*nEdges - - values = split(readline(f)) - n = parse(Int,values[1]) - m = parse(Int,values[2]) - - xMesh[i] = nodes[n,1] - xMesh[i+1] = nodes[m,1] - xMesh[i+2] = NaN - - yMesh[i] = nodes[n,2] - yMesh[i+1] = nodes[m,2] - yMesh[i+2] = NaN - - end - return xMesh, yMesh - end - elseif meshFileFormat == "ISM" - open(meshFile,"r") do f - # there is no header to read so directly read in - line = readline(f) # Numbers of corners, elements and boundary polynomial order - values = split(line) - - nNodes = parse(Int,values[1]) - nElements = parse(Int,values[2]) - nBndy = parse(Int, values[3]) -# -# Read the nodes -# - nodes = zeros(Float64,nNodes,2) - for i = 1:nNodes - values = split(readline(f)) - for j = 1:2 - nodes[i,j] = parse(Float64, values[j]) - end - end -# -# Read the element ids (and skip all the boundary information) -# - elements = zeros(Int64,nElements,4) - temp = zeros(Int64, 4) - for i = 1:nElements - values = split(readline(f)) - for j = 1:4 - elements[i,j] = parse(Int64, values[j]) - end - values = split(readline(f)) - for j = 1:4 - temp[j] = parse(Int64, values[j]) - end - if sum(temp) == 0 - # straight-sided edge so just skip the boundary labels - readline(f) - else - # curved edge so skip the boundary polynomial and the labels - for i = 1:nBndy+1 - readline(f) - end - readline(f) - end - end - # convenience mapping for element index corners - p = [[1 2 4 1] - [2 3 3 4]] - # Build the edges. This is only for plotting purposes so we might have some - # repeated edges but we don't care - edge_id = 0 - hash_table = Dict{Int, Int}() - edges = Dict{Int, Any}() - for j in 1:nElements - for k in 1:4 - id1 = elements[j , p[1,k]] - id2 = elements[j , p[2,k]] - key_val = id1 + id2 - edge_id += 1 - push!( hash_table , key_val => edge_id ) - push!( edges , edge_id => [id1 id2] ) - end # k - end # j - # set the total number of edges - nEdges = edge_id - # use the edge information and pull the corner node physical values - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) - edge_id = 0 - for i = 1:3:3*nEdges - edge_id += 1 - current_edge = edges[edge_id] - n = current_edge[1] - m = current_edge[2] - - xMesh[i] = nodes[n,1] - xMesh[i+1] = nodes[m,1] - xMesh[i+2] = NaN - - yMesh[i] = nodes[n,2] - yMesh[i+1] = nodes[m,2] - yMesh[i+2] = NaN - end - return xMesh, yMesh - end - elseif meshFileFormat == "ABAQUS" - # read in the entire file - file_lines = readlines(open(meshFile)) - # obtain the number of corners and elements in a circuitous way due to the ABAQUS format - # number of corner nodes - file_idx = findfirst(contains("*ELEMENT"), file_lines) - 1 - current_line = split(file_lines[file_idx], ",") - nNodes = parse(Int, current_line[1]) - # number of elements - file_idx = findfirst(contains("** ***** HOHQMesh boundary information ***** **"), file_lines) - 1 - current_line = split(file_lines[file_idx], ",") - nElements = parse(Int, current_line[1]) -# -# Read in the nodes -# - nodes = zeros(Float64,nNodes,2) - file_idx = 4 - for i in 1:nNodes - current_line = split(file_lines[file_idx], ",") - for j = 2:3 - nodes[i, j-1] = parse(Float64, current_line[j]) - end - file_idx += 1 - end # i -# -# Read the element ids (and skip all the boundary information) -# - elements = zeros(Int64,nElements,4) - # eat the element header - file_idx += 1 - for i = 1:nElements - current_line = split(file_lines[file_idx], ",") - for j = 2:5 - elements[i,j-1] = parse(Int64, current_line[j]) - end - file_idx += 1 - end - # convenience mapping for element index corners - p = [[1 2 4 1] - [2 3 3 4]] - # Build the edges. This is only for plotting purposes so we might have some - # repeated edges but we don't care - edge_id = 0 - hash_table = Dict{Int, Int}() - edges = Dict{Int, Any}() - for j in 1:nElements - for k in 1:4 - id1 = elements[j , p[1,k]] - id2 = elements[j , p[2,k]] - key_val = id1 + id2 - edge_id += 1 - push!( hash_table , key_val => edge_id ) - push!( edges , edge_id => [id1 id2] ) - end # k - end # j - # set the total number of edges - nEdges = edge_id - # use the edge information and pull the corner node physical values - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) - edge_id = 0 - for i = 1:3:3*nEdges - edge_id += 1 - current_edge = edges[edge_id] - n = current_edge[1] - m = current_edge[2] - - xMesh[i] = nodes[n,1] - xMesh[i+1] = nodes[m,1] - xMesh[i+2] = NaN - - yMesh[i] = nodes[n,2] - yMesh[i+1] = nodes[m,2] - yMesh[i+2] = NaN - end - return xMesh, yMesh - end -end - -function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) - lines!(plt[1,1], xMesh,yMesh) -end diff --git a/HQMTool/Source/Viz/VizProject.jl b/HQMTool/Source/Viz/VizProject.jl deleted file mode 100644 index 18444d9a..00000000 --- a/HQMTool/Source/Viz/VizProject.jl +++ /dev/null @@ -1,195 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -using GLMakie - -const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 -const REFINEMENTS = 8; const ALL = 15 -""" - plotProject!(proj::Project, plotOptions::Int = 0) - -Plot objects specified by the `plotOptions`. Construct the `plotOptions` by the sum -of what is to be drawn from the choices `MODEL`, `GRID`, `MESH`, `REFINEMENTS`. - -Example: To plot the model and the grid, `plotOptions = MODEL + GRID`. To plot -just the mesh, `plotOptions = MESH`. - -To plot everything, `plotOptions = MODEL + GRID + MESH + REFINEMENTS` - -Contents are overlayed in the order: GRID, MESH, MODEL, REFINEMENTS -""" -function plotProject!(proj::Project, plotOptions::Int = 0) - - if isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) - end - plt = proj.plt - ax = plt[1,1] = Axis(plt) - - plotTheModel = ((plotOptions & MODEL) != 0) - plotTheGrid = ((plotOptions & GRID) != 0) - plotTheMesh = ((plotOptions & MESH) != 0) - plotTheRefinements = ((plotOptions & REFINEMENTS) != 0) - proj.plotOptions = plotOptions -# -# Plot the grid -# - if plotTheGrid && hasBackgroundGrid(proj) - if proj.backgroundGridShouldUpdate # Lazy evaluation of the background grid - proj.bounds = projectBounds(proj) - proj.xGrid, proj.yGrid = projectGrid(proj) - proj.backgroundGridShouldUpdate = false - end - nX = length(proj.xGrid) - nY = length(proj.yGrid) - z = zeros(Float64,nX,nY) - wireframe!(plt[1,1],proj.xGrid,proj.yGrid,z) - end -# -# Plot the mesh -# - if plotTheMesh - # Lazy creation of mesh plotting arrays - if proj.meshShouldUpdate || (isempty(proj.xMesh) && isempty(proj.yMesh)) - meshFileName = getMeshFileName(proj) - if isfile(meshFileName) - fileFormat = getMeshFileFormat(proj) - proj.xMesh, proj.yMesh = getMeshFromMeshFile(meshFileName, fileFormat) - plotMesh(plt, proj.xMesh, proj.yMesh) - end - proj.meshShouldUpdate = false - else - plotMesh(plt, proj.xMesh, proj.yMesh) - end - end -# -# Plot the model -# - if plotTheModel -# -# Plot the outer innerBoundaries -# - if !isempty(proj.outerBndryNames) - plotNames = ["Outer."*s for s in proj.outerBndryNames] - plotChain!(plt,proj.outerBndryPoints, plotNames) - end -# -# Plot the inner innerBoundaries -# - if !isempty(proj.innerBoundaryChainNames) - for i = 1:length(proj.innerBoundaryChainNames) - innerBndryPts = proj.innerBoundaryPoints[i] - innerBndryNames = [ proj.innerBoundaryChainNames[i]*"."*s for s in proj.innerBoundaryNames[i]] - plotChain!(plt,innerBndryPts, innerBndryNames) - end - end - if !isempty(proj.outerBndryNames) || !isempty(proj.innerBoundaryChainNames) - plt[1,2] = Legend(plt, ax, "Curves", framevisible = false, labelsize = 24, titlesize = 28) - end - - end -# -# Plot refinement regions -# - if plotTheRefinements - if !isempty(proj.refinementRegionNames) - plotRefinement(plt,proj.refinementRegionPoints, - proj.refinementRegionNames, - proj.refinementRegionLoc) - end - end -# -# Display the plot -# - ax.aspect = DataAspect() - display(plt) -end -""" - updatePlot!(proj::Project) - -This version replots the figure with the current options. Legacy. -""" -function updatePlot!(proj::Project) - if !isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) - plotOptions = proj.plotOptions - plotProject!(proj, plotOptions) - end -end -""" -updatePlot!(proj::Project, plotOptions::Int) - -Replot with the new plotOptions = combinations (sums) of - - GRID, MESH, MODEL, REFINEMENTS - -Example: updatePlot(p, MESH + MODEL) -""" -function updatePlot!(proj::Project, plotOptions::Int) - if !isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) - plotProject!(proj, plotOptions) - end -end - -function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) - x = chainPoints[1] - plotCurve(plt, x, labels[1]) - - s = length(labels) - - for i = 2:s - x = chainPoints[i] - plotCurve(plt,x,labels[i]) - end -end - -function plotCurve(plt, points::Matrix{Float64}, label::String) - lines!(plt[1,1],points[:,1],points[:,2], label = label, linewidth = 5 ) - s = size(points) - np = div(s[1], 2, RoundNearest) - if s[1] == 3 - np = 2 - end - dx = points[np+1,1] - points[np-1,1] - dy = points[np+1,2] - points[np-1,2] - theta = atan(dy,dx) - if(abs(dy) <= 0.0001) #Not pretty - theta = 0.0 - end - pp = (points[np,1],points[np,2]) - text!(plt[1,1],label,position = pp, align = (:center,:center), rotation = theta ) -end - -function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String}, loc::Array{Array{Float64}}) - - for (i,reg) in enumerate(points) - lines!(plt[1,1],reg[:,1],reg[:,2], label = label[i], linewidth = 5, linestyle = :dot, color=:black ) - p = loc[i] - pp = (p[1],p[2]) - text!(plt[1,1],label[i],position = pp, align = (:center,:center)) - end -end From 30c951b878b539ef541d65f3aaaba67d0b554ba8 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 11:12:41 +0100 Subject: [PATCH 027/164] debug plotting of all three mesh file formats --- src/HQMTool.jl | 105 +++++++++++++++---------------- src/Project/BackgroundGridAPI.jl | 42 ++++++------- src/Viz/VizMesh.jl | 2 +- 3 files changed, 74 insertions(+), 75 deletions(-) diff --git a/src/HQMTool.jl b/src/HQMTool.jl index f8086493..cc5171f6 100644 --- a/src/HQMTool.jl +++ b/src/HQMTool.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -90,52 +90,51 @@ function iceCreamConeVerbose(folder::String) # # Show the model and grid # - plotProject!(p, MODEL+GRID) + plotProject!(p, MODEL+GRID) # # Generate the mesh and plot # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) -return p + return p end function iceCreamCone(folder::String) - # - # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `path`. - # - p = newProject("IceCreamCone",folder) - # - # Outer boundary - # - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) - # - # Inner boundary - # - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") - # - # To mesh, a background grid is needed - # - addBackgroundGrid!(p, [0.5,0.5,0.0]) - # - # Show the model and grid - # - plotProject!(p, MODEL+GRID) - # - # Generate the mesh and plot - # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) +# +# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# written to `path`. +# + p = newProject("IceCreamCone",folder) +# +# Outer boundary +# + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) +# +# Inner boundary +# + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") +# +# To mesh, a background grid is needed +# + addBackgroundGrid!(p, [0.5,0.5,0.0]) +# +# Show the model and grid +# + plotProject!(p, MODEL+GRID) +# +# Generate the mesh and plot +# + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) - return p + return p end diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 6338d48a..af9fe849 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -42,7 +42,7 @@ end """ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) -Add the background grid block with bounding box = [TOP, LEFT, BOTTOM, RIGHT] +Add the background grid block with bounding box = [TOP, LEFT, BOTTOM, RIGHT] and the number of intervals in each diredction. Use this when there is _no_ outer boundary defined in the model. """ @@ -51,7 +51,7 @@ function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) disableNotifications() proj.bounds = box proj.userBounds = deepcopy(box) - + dx = zeros(Float64,3) dx[1] = (box[RIGHT] - box[LEFT])/N[1] dx[2] = (box[TOP] - box[BOTTOM])/N[2] @@ -69,9 +69,9 @@ end """ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) -Add the background grid block using the left corner, x0, the +Add the background grid block using the left corner, x0, the grid size dx, and the number of intervals in each direction. Use this when there -is _no_ outer boundary defined in the model. This version mimics HOHQMesh's +is _no_ outer boundary defined in the model. This version mimics HOHQMesh's backgroundGrid block, but the version addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) @@ -141,7 +141,7 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Flo registerWithUndoManager(proj,setBackgroundGridSize!, (oldSpacing[1],oldSpacing[2],0.0),"Set Background Grid Spacing") return nothing - end +end """ getBackgroundGridSize(proj::Project) @@ -172,7 +172,7 @@ function getBackgroundGridLowerLeft(proj::Project) end """ function getBackgroundGridSteps(proj::Project) - + Returns the [Nx,Ny,Nz] for the background grid. """ function getBackgroundGridSteps(proj::Project) @@ -197,10 +197,10 @@ function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) oldLowerLeft = realArrayForKeyFromDictionary("x0",bgDict) registerWithUndoManager(proj,setBackgroundGridLowerLeft!, (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") - end + end x0Str = @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) - bgDict["x0"] = x0Str + bgDict["x0"] = x0Str postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing end diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index ac8bbb69..d4f3aee3 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -24,7 +24,7 @@ --- End License =# -function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::String) +function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractString) if meshFileFormat == "ISM-V2" open(meshFile,"r") do f From 3ba64ed896e80dd4e92c32169ef2b15fb08abb3c Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 11:33:20 +0100 Subject: [PATCH 028/164] remove remaining duplicate source files and HQMTool folder. All files now live in src --- .../ControlFile/ControlFileOperations.jl | 316 ------------ HQMTool/Source/Curves/CurveOperations.jl | 243 --------- HQMTool/Source/Curves/Spline.jl | 131 ----- HQMTool/Source/Mesh/Meshing.jl | 53 -- HQMTool/Source/Misc/DictionaryOperations.jl | 89 ---- HQMTool/Source/Misc/NotificationCenter.jl | 107 ---- HQMTool/Source/Model/Geometry.jl | 93 ---- HQMTool/Source/Project/BackgroundGridAPI.jl | 265 ---------- HQMTool/Source/Project/ControlInputAPI.jl | 60 --- HQMTool/Source/Project/CurvesAPI.jl | 450 ----------------- HQMTool/Source/Project/Generics.jl | 164 ------ HQMTool/Source/Project/ModelAPI.jl | 427 ---------------- HQMTool/Source/Project/Project.jl | 409 --------------- .../Source/Project/RefinementRegionsAPI.jl | 476 ------------------ HQMTool/Source/Project/SmootherAPI.jl | 118 ----- HQMTool/Source/Project/Undo.jl | 142 ------ 16 files changed, 3543 deletions(-) delete mode 100644 HQMTool/Source/ControlFile/ControlFileOperations.jl delete mode 100644 HQMTool/Source/Curves/CurveOperations.jl delete mode 100644 HQMTool/Source/Curves/Spline.jl delete mode 100644 HQMTool/Source/Mesh/Meshing.jl delete mode 100644 HQMTool/Source/Misc/DictionaryOperations.jl delete mode 100644 HQMTool/Source/Misc/NotificationCenter.jl delete mode 100644 HQMTool/Source/Model/Geometry.jl delete mode 100644 HQMTool/Source/Project/BackgroundGridAPI.jl delete mode 100644 HQMTool/Source/Project/ControlInputAPI.jl delete mode 100644 HQMTool/Source/Project/CurvesAPI.jl delete mode 100644 HQMTool/Source/Project/Generics.jl delete mode 100644 HQMTool/Source/Project/ModelAPI.jl delete mode 100644 HQMTool/Source/Project/Project.jl delete mode 100644 HQMTool/Source/Project/RefinementRegionsAPI.jl delete mode 100644 HQMTool/Source/Project/SmootherAPI.jl delete mode 100644 HQMTool/Source/Project/Undo.jl diff --git a/HQMTool/Source/ControlFile/ControlFileOperations.jl b/HQMTool/Source/ControlFile/ControlFileOperations.jl deleted file mode 100644 index 2e38c2be..00000000 --- a/HQMTool/Source/ControlFile/ControlFileOperations.jl +++ /dev/null @@ -1,316 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -#= - ImportControlFile(fileName::String) - -The control file reader parses the control file and returns a Control file dictionary. - -@author: davidkopriva - -A Control file dictionary contains the keys - TYPE - CONTROL_INPUT - MODEL - -TYPE is a string naming the type (class) of object stored - -The CONTROL_INPUT contains the blocks - TYPE - RUN_PARAMETERS - MESH_PARAMETERS - SPRING_SMOOTHER - REFINEMENT_REGIONS - REFINEMENT_REGIONS contains a ["LIST"] of - REFINEMENT_CENTER - REFINEMENT_LINE - SCALE_TRANSFORMATION - ROTATION_TRANSFORMATION - SIMPLE_EXTRUSION - SIMPLE_ROTATION - SWEEP_ALONG_CURVE - -The MODEL dictionary contains the keys - TYPE - OUTER_BOUNDARY - OUTER_BOUNDARY contains a ["LIST"] of - PARAMETRIC_EQUATION_CURVE - SPLINE_CURVE - END_POINTS_LINE - CIRCULAR_ARC - INNER_BOUNDARIES - The INNER_BOUNDARIES block contains a ["LIST"] of - CHAIN - SWEEP_CURVE - SWEEP_SCALE_FACTOR - TOPOGRAPHY - -A CHAIN block contains a ["LIST"] of - PARAMETRIC_EQUATION_CURVE - SPLINE_CURVE - END_POINTS_LINE - CIRCULAR_ARC - -A PARAMETRIC_EQUATION_CURVE dictionary contains the keys - TYPE - name - xEqn - yEqn - zEqn - -=# - -# Four objects store their members as lists rather than -# as dictionaries - -blocksThatStoreLists = Set(["OUTER_BOUNDARY", - "REFINEMENT_REGIONS" , - "INNER_BOUNDARIES", - "CHAIN"]) - -blockNameStack = [] -blockRegex = r"(?<=\{).+?(?=\})" -# -#--------------- MAIN ENTRY ----------------------------------------------- -# -function ImportControlFile(fileName::String) - controlDict = Dict{String,Any}() - open(fileName,"r") do controlFile - performImport(controlDict, controlFile) - end - return controlDict -end - -function WriteControlFile(controlDict::Dict{String,Any}, fileName::String) - open(fileName,"w") do controlFile - indent = "" - WriteDictionary(controlDict, controlFile, indent) - println(controlFile,"\\end{FILE}") - end -end -# -#------------- END MAIN ENTRY ------------------------------------------ -# -function performImport(collection, f::IOStream) - - for line in eachline(f) -# -# ---------------- -# Start of a block -# ---------------- -# - if occursin("begin{",line) - blockNameMatch = match(blockRegex,line) - if blockNameMatch === nothing - error("Block name not found in string: " * line) - else # Start new collection - blockName = blockNameMatch.match - push!(blockNameStack, blockName) -# -# A SPLINE_DATA block is special and is read in separately -# into an array and saved in the spline curve dictionary -# - if blockName == "SPLINE_DATA" - ImportSplineData( collection, f) - continue - end - - newBlock = Dict{String,Any}() - newBlock["TYPE"] = blockName - addToCollection(collection, blockName, newBlock) -# -# Some blocks store items in a list -# - if in(blockName, blocksThatStoreLists) - newBlock["LIST"] = Dict{String,Any}[] -# -# If the block defines a chain, get its name -# - if blockName == "CHAIN" - nextLine = readline(f) - kvp = keyAndValueOnLine(nextLine) - if kvp === nothing - error("Key-value pair not found in string: " * nextLine) - end - addToCollection(newBlock,kvp[1],kvp[2]) - end - performImport(newBlock["LIST"],f) - else - performImport(newBlock,f) - end - end -# -# -------------- -# End of a block -# -------------- -# - elseif occursin("end{",line) - blockNameMatch = match(blockRegex,line) - blockName = blockNameMatch.match - if blockName == "FILE" - return - end - if length(blockNameStack) == 0 - error("Extra end statement found: " * line) - end - if blockNameMatch === nothing - error("Block name not found in string: " * line) - else - stackValue::String = blockNameStack[end] - if cmp(blockName,stackValue) == 0 - pop!(blockNameStack) - else - error("Block name end $blockName does not match current block $stackValue") - end - if blockName == "SPLINE_DATA" - continue - else - return - end - end -# -# ---------------------- -# Comment or blank lines -# ---------------------- -# - elseif isempty(line) - continue - elseif line[1] == '%' - continue -# -# ------------------------- -# Block body key-value pair -# ------------------------- -# - else - kvp = keyAndValueOnLine(line) - if kvp === nothing - error("Key-value pair not found in string: " * line) - end - addToCollection(collection,kvp[1],kvp[2]) - end - end -end -# -#-------------------------------------------------------------------------------------- -# -function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::String) - - deepIndent = " " * indent - for (key, value) in controlDict - if isa(value, AbstractDict) - println(f,indent,"\\begin{$key}") - if in(key,blocksThatStoreLists) - list = value["LIST"] - StepThroughList(list,f, deepIndent) - else - WriteDictionary(value,f, deepIndent) - end - println(f,indent,"\\end{$key}") - elseif isa(value, AbstractString) - if key != "TYPE" - println(f,indent,"$key = $value") - end - elseif isa(value, AbstractArray) - if key == "LIST" - StepThroughList(value,f, deepIndent) - elseif key == "SPLINE_DATA" - println(f,indent,"\\begin{$key}") - arraySize = size(value) - for j = 1:arraySize[1] - println(f,deepIndent, " ", value[j,1], " ", value[j,2], " ", value[j,3], " ", value[j,4]) - end - println(f,indent,"\\end{$key}") - end - end - end -end -# -#-------------------------------------------------------------------------------------- -# -function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) - deepIndent = " " * indent - for dict in lst - dtype = dict["TYPE"] - println(f,indent, "\\begin{$dtype}") - WriteDictionary(dict,f, deepIndent) - println(f,indent, "\\end{$dtype}") - end -end -# -#-------------------------------------------------------------------------------------- -# -function keyAndValueOnLine(s) - indxOfEqual = findfirst("=",s) - if indxOfEqual === nothing - return nothing - end - key = strip(s[1:indxOfEqual.start-1],[' ','\t']) - value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) - return (key,value) -end -# -#-------------------------------------------------------------------------------------- -# -function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::AbstractString) - dict[k] = v -end -# -#-------------------------------------------------------------------------------------- -# -function addToCollection(c::Array, k::AbstractString, v::Any) - push!(c,v) -end -# -#-------------------------------------------------------------------------------------- -# -function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::Dict{String,Any}) - dict[k] = v -end -# -#-------------------------------------------------------------------------------------- -# -function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) - - if !haskey(splineDict, "nKnots") - @warn "Spline block must define nKnots before SPLINE_DATA. Skipping..." - line = "" - while !occursin("end{SPLINE_DATA",line) #BUG This will read one too many lines - line = readline(f) - end - end - - knotString = splineDict["nKnots"] - nKnots = parse(Int64,knotString) - splineDataArray = zeros(Float64,nKnots,4) - for i = 1:nKnots - currentLine = split(readline(f)) - for j = 1:4 - splineDataArray[i,j] = parse(Float64,currentLine[j]) - end - end - splineDict["SPLINE_DATA"] = splineDataArray -end diff --git a/HQMTool/Source/Curves/CurveOperations.jl b/HQMTool/Source/Curves/CurveOperations.jl deleted file mode 100644 index a7de2eba..00000000 --- a/HQMTool/Source/Curves/CurveOperations.jl +++ /dev/null @@ -1,243 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -using Base: String, Int64, Float64 - -argRegex = r"(?<=\().+?(?=\))" - -function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Array{Float64}, points::Array{Float64,2}) - fctr::Float64 = 1.0 - if units == "degrees" - fctr = pi/180.0 - end - - theta::Float64 = 0.0 - for i = 1:length(t) - theta = thetaStart + (thetaEnd - thetaStart)*t[i] - points[i,1] = center[1] + r*cos(theta*fctr) - points[i,2] = center[2] + r*sin(theta*fctr) - end -end - -function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, - units::AbstractString, t::Float64, point::Array{Float64}) - fctr::Float64 = 1.0 - if units == "degrees" - fctr = pi/180.0 - end - theta = thetaStart + (thetaEnd - thetaStart)*t - point[1] = center[1] + r*cos(theta*fctr) - point[2] = center[2] + r*sin(theta*fctr) -end - -function endPointsLineCurvePoints(xStart::Array{Float64}, xEnd::Array{Float64}, t::Array{Float64}, points::Array{Float64}) - for i = 1:length(t) - points[i,1:2] = xStart[1:2] + t[i]*(xEnd[1:2] - xStart[1:2]) - end -end - -function endPointsLineCurvePoint(xStart::Array{Float64}, xEnd::Array{Float64}, t::Float64, point::Array{Float64}) - point[1:2] = xStart[1:2] + t*(xEnd[1:2] - xStart[1:2]) -end - -function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Float64,2}) - - argPart,eqString = keyAndValueFromString(xEqn) - xArgM = match(argRegex,argPart) - xArg = Symbol(xArgM.match) - ex = Meta.parse(eqString) - - argPart,eqString = keyAndValueFromString(yEqn) - yArgM = match(argRegex,argPart) - yArg = Symbol(yArgM.match) - ey = Meta.parse(eqString) - - for i = 1:length(t) - points[i,1] = evalWithDict(ex,Dict(xArg=> t[i])) - points[i,2] = evalWithDict(ey,Dict(yArg=> t[i])) - end -end - -function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) - - argPart,eqString = keyAndValueFromString(xEqn) - xArgM = match(argRegex,argPart) - xArg = Symbol(xArgM.match) - ex = Meta.parse(eqString) - - argPart,eqString = keyAndValueFromString(yEqn) - yArgM = match(argRegex,argPart) - yArg = Symbol(yArgM.match) - ey = Meta.parse(eqString) - - point[1] = evalWithDict(ex,Dict(xArg=> t[i])) - point[2] = evalWithDict(ey,Dict(yArg=> t[i])) - -end - -function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Array{Float64,2}) - - xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) - ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) - - sz = size(points) - nPts = sz[1] - t = 0.0 - for i = 1:nPts - t = (i-1)/(nPts-1) - points[i,1] = evalSpline(xSpline,t) - points[i,2] = evalSpline(ySpline,t) - end -end - -function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::Array{Float64}) - - xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) - ySpline = constructSpline(nKnots,splineData[:,1],splineData[:,3]) - - point[1] = evalSpline(xSpline,t) - point[2] = evalSpline(ySpline,t) -end - -function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) - ex = Meta.parse(s) - assignments = [:($sym = $val) for (sym,val) in locals] - eval(:(let $(assignments...); $ex; end)) -end - -function evalWithDict(ex::Expr, locals::Dict{Symbol}) - assignments = [:($sym = $val) for (sym,val) in locals] - eval(:(let $(assignments...); $ex; end)) -end - -function curvePoints(crvDict::Dict{String,Any}, N::Int) - - curveType::String = crvDict["TYPE"] - - if curveType == "PARAMETRIC_EQUATION_CURVE" - xEqn = crvDict["xEqn"] - yEqn = crvDict["yEqn"] - - x = zeros(Float64,N+1,2) - t = zeros(Float64,N+1) - for i = 1:N+1 - t[i] = (i-1)/N - end - peEquationCurvePoints(xEqn,yEqn,t,x) - elseif curveType == "END_POINTS_LINE" - xStart = realArrayForKeyFromDictionary("xStart",crvDict) - xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) - x = zeros(Float64,3,2) - t = zeros(Float64,3) - for i = 1:3 - t[i] = (i-1)/2.0 - end - - endPointsLineCurvePoints(xStart,xEnd,t,x) - elseif curveType == "CIRCULAR_ARC" - center = realArrayForKeyFromDictionary("center",crvDict) - radius = realForKeyFromDictionary("radius",crvDict) - startAngle = realForKeyFromDictionary("start angle",crvDict) - endAngle = realForKeyFromDictionary("end angle",crvDict) - units = crvDict["units"] - - x = zeros(Float64,N+1,2) - t = zeros(Float64,N+1) - for i = 1:N+1 - t[i] = (i-1)/N - end - - arcCurvePoints(center,radius,startAngle,endAngle,units,t,x) - elseif curveType == "SPLINE_CURVE" - nKnots = intForKeyFromDictionary("nKnots",crvDict) - splineData = crvDict["SPLINE_DATA"] - - M = max(N,nKnots*2) - x = zeros(Float64,M+1,2) - t = zeros(Float64,M+1) - for i = 1:M+1 - t[i] = (i-1)/M - end - - splineCurvePoints(nKnots,splineData,x) - else - - end - return x -end - -function chainPoints(chain::Array{Dict{String,Any}}, N::Int) - - x = Any[] - - for crvDict in chain - push!(x,curvePoints(crvDict,N)) - end - return x -end - -function curvePoint(crvDict::Dict{String,Any}, t::Float64) - - curveType::String = crvDict["TYPE"] - - if curveType == "PARAMETRIC_EQUATION_CURVE" - xEqn = crvDict["xEqn"] - yEqn = crvDict["yEqn"] - x = zeros(Float64,3) - peEquationCurvePoint(xEqn,yEqn,t,x) - elseif curveType == "END_POINTS_LINE" - xStart = realArrayForKeyFromDictionary("xStart",crvDict) - xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) - x = zeros(Float64,3) - endPointsLineCurvePoint(xStart,xEnd,t,x) - elseif curveType == "CIRCULAR_ARC" - center = realArrayForKeyFromDictionary("center",crvDict) - radius = realForKeyFromDictionary("radius",crvDict) - startAngle = realForKeyFromDictionary("start angle",crvDict) - endAngle = realForKeyFromDictionary("end angle",crvDict) - units = crvDict["units"] - x = zeros(Float64,3) - arcCurvePoint(center,radius,startAngle,endAngle,units,t,x) - elseif curveType == "SPLINE_CURVE" - nKnots = intForKeyFromDictionary("nKnots",crvDict) - splineData = crvDict["SPLINE_DATA"] - x = zeros(Float64,3) - splineCurvePoint(nKnots,splineData,t,x) - else - - end - return x -end - -function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}) - xFirst = curvePoint(firstCurve,1.0) - xSecond = curvePoint(secondCurve,0.0) - if maximum(abs.(xFirst - xSecond)) < 100*eps(Float64) - return true - else - return false - end -end diff --git a/HQMTool/Source/Curves/Spline.jl b/HQMTool/Source/Curves/Spline.jl deleted file mode 100644 index 6d34f47a..00000000 --- a/HQMTool/Source/Curves/Spline.jl +++ /dev/null @@ -1,131 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -mutable struct Spline - N::Int - x::Array{Float64} - y::Array{Float64} - b::Array{Float64} - c::Array{Float64} - d::Array{Float64} - last::Int -end - -function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) - b = zeros(Float64,N) - c = zeros(Float64,N) - d = zeros(Float64,N) - - Nm1 = N - 1 -# -# Set up tri-diagonal system -# - d[1] = x[2] - x[1] - c[2] = (y[2] - y[1])/d[1] - for i = 2:Nm1 - d[i] = x[i+1] - x[i] - b[i] = 2.0*(d[i-1] + d[i]) - c[i+1] = (y[i+1] - y[i])/d[i] - c[i] = c[i+1] - c[i] - end -# -# end conditions -# - b[1] = -d[1] - b[N] = -d[N-1] - c[1] = c[3]/(x[4] - x[2]) - c[2]/(x[3] - x[1]) - c[N] = c[N-1]/(x[N] - x[N-2]) - c[N-2]/(x[N-1] - x[N-3]) - c[1] = c[1]*d[1]^2/(x[4] - x[1]) - c[N] = -c[N]*d[N-1]^2/(x[N] - x[N-3]) -# -# Forward elimination -# - t = 0.0 - for i = 2:N - t = d[i-1]/b[i-1] - b[i] = b[i] - t*d[i-1] - c[i] = c[i] - t*c[i-1] - end -# -# Back substitution -# - c[N] = c[N]/b[N] - for ib = 1:Nm1 - i = N - ib - c[i] = (c[i] - d[i]*c[i+1])/b[i] - end -# -# Compute polynomial coefficients -# - b[N] = (y[N] - y[Nm1])/d[Nm1] + d[Nm1]*(c[Nm1] + 2.0*c[N]) - for i = 1: Nm1 - b[i] = (y[i+1] - y[i])/d[i] - d[i]*(c[i+1] + 2.0*c[i]) - d[i] = (c[i+1] - c[i])/d[i] - c[i] = 3.0*c[i] - end - c[N] = 3.0*c[N] - d[N] = d[N-1] - - spl = Spline(N,x,y,b,c,d,1) - return spl -end - -function evalSpline(spl::Spline, u::Float64) - N = spl.N - s = 0.0 - i = spl.last - - if i >= N - i = 1 - end - - if spl.x[i] < u <= spl.x[i+1] - dx = u - spl.x[i] - s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) - spl.last = i - return s - end - - i = 1 - j = N+1 - - for ii = 1:N - k = div(i+j,2) - if u < spl.x[k] - j = k - end - if u >= spl.x[k] - i = k - end - if j <= i+1 - break - end - end - dx = u - spl.x[i] - s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) - spl.last = i - return s -end \ No newline at end of file diff --git a/HQMTool/Source/Mesh/Meshing.jl b/HQMTool/Source/Mesh/Meshing.jl deleted file mode 100644 index 15739d62..00000000 --- a/HQMTool/Source/Mesh/Meshing.jl +++ /dev/null @@ -1,53 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -using HOHQMesh - -function generateMesh(proj::Project) -# -# Check to be sure background grid has been created (everhtying else is defaults) -# - controlDict = getControlDict(proj) - if !haskey(controlDict,"BACKGROUND_GRID") - println("A background grid is needed before meshing. Add one and try again.") - return nothing - end - path = mkpath(proj.projectDirectory) - saveProject(proj) - fileName = joinpath(proj.projectDirectory,proj.name)*".control" - mesherOutput = generate_mesh(fileName, output_directory = proj.projectDirectory) - println(mesherOutput) - postNotificationWithName(proj,"MESH_WAS_GENERATED_NOTIFICATION",(nothing,)) - return nothing -end - -function removeMesh!(proj::Project) - meshFile = getMeshFileName(proj) - rm(meshFile) - proj.xMesh = Float64[] - proj.yMesh = Float64[] - postNotificationWithName(proj,"MESH_WAS_DELETED_NOTIFICATION",(nothing,)) -end diff --git a/HQMTool/Source/Misc/DictionaryOperations.jl b/HQMTool/Source/Misc/DictionaryOperations.jl deleted file mode 100644 index 96bbc960..00000000 --- a/HQMTool/Source/Misc/DictionaryOperations.jl +++ /dev/null @@ -1,89 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -#= - Some useful getters for a dictionary -=# -arrayRegex = r"(?<=\[).+?(?=\])" - -function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) - v = d[key] - return parse(Float64,v) -end - -function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) - v = d[key] - return parse(Int64,v) -end - -function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) - v = d[key] - return v -end - -function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) - v = d[key] - values = match(arrayRegex,v) - s = split(values.match,",") - array = [parse(Float64,s[1]),parse(Float64,s[2]),parse(Float64,s[3])] - return array -end - -function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) - v = d[key] - values = match(arrayRegex,v) - s = split(values.match,",") - array = [parse(Int,s[1]),parse(Int,s[2]),parse(Int,s[3])] - return array -end - -function keyAndValueFromString(s) - indxOfEqual = findfirst("=",s) - if indxOfEqual === nothing - return nothing - end - key = strip(s[1:indxOfEqual.start-1],[' ','\t']) - value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) - return (key,value) -end - -function showDescription(d::Dict, pre=1) - todo = Vector{Tuple}() - for (k,v) in d - if typeof(v) <: Dict - push!(todo, (k,v)) - else - println(join(fill(" ", pre)) * "$(repr(k)) => $(repr(v))") - end - end - - for (k,d) in todo - s = "$(repr(k)) => " - println(join(fill(" ", pre)) * s) - showDescription(d, pre+1+length(s)) - end - nothing -end diff --git a/HQMTool/Source/Misc/NotificationCenter.jl b/HQMTool/Source/Misc/NotificationCenter.jl deleted file mode 100644 index b2ae9586..00000000 --- a/HQMTool/Source/Misc/NotificationCenter.jl +++ /dev/null @@ -1,107 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -struct HQMNotification - sender ::Any # Who sent the notification - userInfo ::Tuple # Any necessary data needed -end - -struct HQMNotificationObject - observer::Any - fcn ::Any -end - -HQMNotificationCenter = Dict{String,Vector{HQMNotificationObject}}() -HQMNotificationsON = true - -""" - addObserver(observer::Any, note::String, fnction::Any) - -fnction is the function to be executed (called) when a -notification of name `note` is given. - -The function called upon notification must have the signature -fnction(observer, sender, args...) -""" -function addObserver(observer::Any, note::String, fnction::Any) - - noteObj = HQMNotificationObject(observer,fnction) - if !haskey(HQMNotificationCenter,note) - HQMNotificationCenter[note] = HQMNotificationObject[] - end - push!(HQMNotificationCenter[note],noteObj) -end -""" - unRegisterForNotification(observer::Any, note::String) - -Remove the observer from being notified by the notification `note` -""" -function unRegisterForNotification(observer::Any, note::String) - if haskey(HQMNotificationCenter,note) - global observers = HQMNotificationCenter[note] - - for i = 1:length(observers) - global noteObj = observers[i] - noteObserver = noteObj.observer - if noteObserver === observer - deleteat!(observers,i) - break - end - end - if isempty(observers) - delete!(HQMNotificationCenter,note) - end - end -end -""" - postNotificationWithName(sender::Any, name::String, userInfo::Tuple) - -Executes the function associated with the observer for the notification `note` -""" -function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) - if haskey(HQMNotificationCenter,note) && HQMNotificationsON - global observers = HQMNotificationCenter[note] - - for i = 1:length(observers) - global noteObj = observers[i] - f = noteObj.fcn - observer = noteObj.observer - if isnothing(userInfo[1]) - f(observer,sender) - else - f(observer,sender,userInfo...) - end - end - end -end - -function enableNotifications() - global HQMNotificationsON = true -end - -function disableNotifications() - global HQMNotificationsON = false -end diff --git a/HQMTool/Source/Model/Geometry.jl b/HQMTool/Source/Model/Geometry.jl deleted file mode 100644 index 71a99954..00000000 --- a/HQMTool/Source/Model/Geometry.jl +++ /dev/null @@ -1,93 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -const TOP = 1; const LEFT = 2; const BOTTOM = 3; const RIGHT = 4 - -""" -curveBounds(crvPoints::Array{Float64,2}) - -Find the bounds of a single curve, discretized as an array -""" -function curveBounds(crvPoints::Array{Float64,2}) - - s = size(crvPoints) - top = -Inf64 - left = Inf64 - bottom = Inf64 - right = -Inf64 - - for i = 1:s[1] - right = max(right,crvPoints[i,1]) - left = min(left,crvPoints[i,1]) - top = max(top,crvPoints[i,2]) - bottom = min(bottom,crvPoints[i,2]) - end - - bounds = zeros(Float64,4) - bounds[TOP] = top - bounds[LEFT] = left - bounds[BOTTOM] = bottom - bounds[RIGHT] = right - - return bounds -end - -function chainBounds(chain::Array{Any}) - bounds = emptyBounds() - for crv in chain - crvBounds = curveBounds(crv) - bounds = bboxUnion(bounds,crvBounds) - end - return bounds -end - -""" - bboxUnion(box1::Array{Float64}, box2::Array{Float64}) - -Returns the union of two bounding boxes -""" -function bboxUnion(box1::Array{Float64}, box2::Array{Float64}) - union = zeros(Float64,4) - union[TOP] = max(box1[TOP] ,box2[TOP]) - union[LEFT] = min(box1[LEFT] ,box2[LEFT]) - union[BOTTOM] = min(box1[BOTTOM],box2[BOTTOM]) - union[RIGHT] = max(box1[RIGHT] ,box2[RIGHT]) - - return union -end -""" - -Returns an array that will always be ignored when unioned with -another bounding box. -""" -function emptyBounds() - emptee = zeros(Float64,4) - emptee[TOP] = -Inf64 - emptee[LEFT] = Inf64 - emptee[BOTTOM] = Inf64 - emptee[RIGHT] = -Inf64 - return emptee -end diff --git a/HQMTool/Source/Project/BackgroundGridAPI.jl b/HQMTool/Source/Project/BackgroundGridAPI.jl deleted file mode 100644 index 687038af..00000000 --- a/HQMTool/Source/Project/BackgroundGridAPI.jl +++ /dev/null @@ -1,265 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -""" - addBackgroundGrid(proj::Project, bgSize::Array{Float64}) - -Add the background grid block with the grid size to be a 3-vector. Use this when there -is an outer boundary defined in the model. -""" -function addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) - disableUndo() - disableNotifications() - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - setBackgroundGridSize!(proj, bgSize, "background grid size") - enableUndo() - registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") - enableNotifications() - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) - -Add the background grid block with bounding box = [TOP, LEFT, BOTTOM, RIGHT] -and the number of intervals in each diredction. Use this when there -is _no_ outer boundary defined in the model. -""" -function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - disableUndo() - disableNotifications() - proj.bounds = box - proj.userBounds = deepcopy(box) - - dx = zeros(Float64,3) - dx[1] = (box[RIGHT] - box[LEFT])/N[1] - dx[2] = (box[TOP] - box[BOTTOM])/N[2] - - setBackgroundGridSize!(proj, dx, "dx") - setBackgroundGridLowerLeft!(proj,[box[LEFT], box[BOTTOM], 0.0]) - setBackgroundGridSteps!(proj,N) - enableUndo() - registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") - enableNotifications() - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end - -""" - addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - -Add the background grid block using the left corner, x0, the -grid size dx, and the number of intervals in each direction. Use this when there -is _no_ outer boundary defined in the model. This version mimics HOHQMesh's -backgroundGrid block, but the version - - addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) - -is a lot easier to use. - -TODO: Change HOHQMesh and delete this way to specify the domain and use the bounding box one instead. - -""" -function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - disableUndo() - disableNotifications() - setBackgroundGridSize!(proj, dx, "dx") - setBackgroundGridLowerLeft!(proj,x0) - setBackgroundGridSteps!(proj,N) - proj.userBounds[TOP] = x0[2] + N*dx[2] - proj.userBounds[LEFT] = x0[1] - proj.userBounds[BOTTOM] = x0[2] - proj.userBounds[RIGHT] = x0[1] + N*dx[1] - enableUndo() - enableNotifications() - registerWithUndoManager(proj,removeBackgroundGrid!,(nothing,),"Add Background Grid") - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end - -""" - removeBackgroundGrid!(proj::Project) - -Remove the background grid block from the project. -""" -function removeBackgroundGrid!(proj::Project) - cDict = getControlDict(proj) - registerWithUndoManager(proj,addBackgroundGrid!,(cDict,),"Delete Background Grid") - delete!(cDict,"RUN_PARAMETERS") - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end - -""" - setBackgroundGridSpacing!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) - -User facing function -""" -function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - - newSize = [dx,dy] - if haskey(bgDict,"dx") - oldSpacing = realArrayForKeyFromDictionary("dx", bgDict) - setBackgroundGridSize!(proj, newSize, "dx") - # With the "corner+intervals" setting of the outer boundary deprecated, keep - # the original bounds fixed. - x0 = realArrayForKeyFromDictionary("x0",bgDict) - Nx = round(Int,(proj.userBounds[RIGHT] - proj.userBounds[LEFT]) /dx[1]) - Ny = round(Int,(proj.userBounds[TOP] - proj.userBounds[BOTTOM])/dx[2]) - N = [Nx,Ny,0] - disableNotifications() - setBackgroundGridSteps!(proj,N) - enableNotifications() - else - oldSpacing = realArrayForKeyFromDictionary("background grid size", bgDict) - setBackgroundGridSize!(proj, newSize, "background grid size") - end - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - registerWithUndoManager(proj,setBackgroundGridSize!, - (oldSpacing[1],oldSpacing[2],0.0),"Set Background Grid Spacing") - return nothing - end -""" - getBackgroundGridSize(proj::Project) - -Returns the background grid size array. -""" -function getBackgroundGridSize(proj::Project) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - if haskey(bgDict,"dx") - return realArrayForKeyFromDictionary("dx",bgDict) - elseif haskey(bgDict,"background grid size") - return realArrayForKeyFromDictionary("background grid size",bgDict) - else - return nothing - end -end -""" - function getBackgroundGridLowerLeft(proj::Project) - -Returns the [x,y] of the lower left point of thebackground grid. -""" -function getBackgroundGridLowerLeft(proj::Project) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - if haskey(bgDict,"x0") - return realArrayForKeyFromDictionary("x0",bgDict) - else - return nothing - end -end -""" - function getBackgroundGridLowerLeft(proj::Project) - -Returns the [x,y,z] of the lower left point of thebackground grid. -""" -function getBackgroundGridSteps(proj::Project) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - if haskey(bgDict,"N") - return realIntForKeyFromDictionary("N",bgDict) - else - return nothing - end -end -""" - setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) - -Set the lower left location of the background grid for problems that have no -outer boundary. -""" -function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) - - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - - if haskey(bgDict,"x0") - oldLowerLeft = realArrayForKeyFromDictionary("x0",bgDict) - registerWithUndoManager(proj,setBackgroundGridLowerLeft!, - (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") - end - - x0Str = @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) - bgDict["x0"] = x0Str - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end -""" -setBackgroundGridSteps!(proj::Project, N::Array{Int}) - -Set how many steps of size setBackgroundGridSpacing in each direction the background grid extends from the -lower left. -""" -function setBackgroundGridSteps!(proj::Project, N::Array{Int}) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - - if haskey(bgDict,"N") - oldN = intArrayForKeyFromDictionary("N",bgDict) - registerWithUndoManager(proj,setBackgroundGridSteps!, - (oldN[1],oldN[2],oldN[3]),"Set Background Steps") - end - - NStr = @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) - bgDict["N"] = NStr - - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end -""" -setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) -""" -function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) - setBackgroundGridSize!(proj, dx[1], dx[2], key) - return nothing -end -""" -setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) -""" -function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) - bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") - - if haskey(bgDict,key) - oldDx = realArrayForKeyFromDictionary(key,bgDict) - registerWithUndoManager(proj,setBackgroundGridSize!, - (oldDx[1],oldDx[2],oldDx[3]),"Set Background Size") - end - - dxStr = @sprintf("[%f,%f,%f]", dx, dy, 0.0) - bgDict[key] = dxStr - postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) - return nothing -end - -""" - addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) - -Used only for undo/redo. -""" -function addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) - controlDict = getControlDict(proj) - controlDict["BACKGROUND_GRID"] = dict - return nothing -end - diff --git a/HQMTool/Source/Project/ControlInputAPI.jl b/HQMTool/Source/Project/ControlInputAPI.jl deleted file mode 100644 index 33ec96e4..00000000 --- a/HQMTool/Source/Project/ControlInputAPI.jl +++ /dev/null @@ -1,60 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -function getControlDict(proj::Project) - if haskey(proj.projectDictionary,"CONTROL_INPUT") - return proj.projectDictionary["CONTROL_INPUT"] - else - controlDict = Dict{String,Any}() - proj.projectDictionary["CONTROL_INPUT"] = controlDict - controlDict["TYPE"] = "CONTROL_INPUT" - return controlDict - end -end - -function getDictInControlDictNamed(proj::Project,name::String) - controlDict = getControlDict(proj) - - if haskey(controlDict,name) - return controlDict[name] - else - d = Dict{String,Any}() - controlDict[name] = d - d["TYPE"] = name - return d - end -end - -function getListInControlDictNamed(proj::Project,name::String) - dict = getDictInControlDictNamed(proj::Project,name::String) - if haskey(dict,"LIST") - return dict["LIST"] - else - lst = [] - dict["LIST"] = lst - return lst - end -end diff --git a/HQMTool/Source/Project/CurvesAPI.jl b/HQMTool/Source/Project/CurvesAPI.jl deleted file mode 100644 index 090e56d5..00000000 --- a/HQMTool/Source/Project/CurvesAPI.jl +++ /dev/null @@ -1,450 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -""" - newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - -Creates and returns a new parametricEquationCurve in the form of a Dictionary -""" -function newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - - crv = Dict{String,Any}() - crv["TYPE"] = "PARAMETRIC_EQUATION_CURVE" - disableNotifications() - disableUndo() - setCurveName!(crv,name) - setXEqn!(crv,xEqn) - setYEqn!(crv,yEqn) - setZEqn!(crv,zEqn) - enableUndo() - enableNotifications() - return crv -end -""" - newEndPointsLineCurve(name::String, xStart::Array{Float64},xEnd::Array[Float64]) - -Creates and returns a new curve defined by its end points in the form of a Dictionary -""" -function newEndPointsLineCurve(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - crv = Dict{String,Any}() - crv["TYPE"] = "END_POINTS_LINE" - disableNotifications() - disableUndo() - setCurveName!(crv,name) - setStartPoint!(crv,xStart) - setEndPoint!(crv,xEnd) - enableNotifications() - enableUndo() - return crv -end -""" - newCircularArcCurve(name::String, center::Array{Float64}, - startAngle::Float64, endAngle::Float64, - units::String) - -Creates and returns a new circular arc curve in the form of a Dictionary -""" -function newCircularArcCurve(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String = "degrees") - - arc = Dict{String,Any}() - arc["TYPE"] = "CIRCULAR_ARC" - disableNotifications() - disableUndo() - setCurveName!(arc,name) - setArcUnits!(arc,units) - setArcCenter!(arc,center) - setArcStartAngle!(arc,startAngle) - setArcEndAngle!(arc,endAngle) - setArcRadius!(arc,radius) - enableNotifications() - enableUndo() - return arc -end -""" - newSplineCurve(name::String, nKnots::Int, data::Array{Float64,4}) - -Returns a spline curve given the number of knots and the array of knots. -""" -function newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) - spline = Dict{String,Any}() - spline["TYPE"] = "SPLINE_CURVE" - disableNotifications() - disableUndo() - setCurveName!(spline,name) - setSplineNKnots!(spline,nKnots) - setSplinePoints!(spline,data) - enableNotifications() - enableUndo() - return spline -end -""" - newSplineCurve(name::String, dataFile::String) - -Returns a spline curve given a data file that contains the number of knots -on the first line, and the spline data following that. -""" -function newSplineCurve(name::String, dataFile::String) - - spline = Dict{String,Any}() - open(dataFile,"r") do f - nKnots = parse(Int,readline(f)) - splineDataArray = zeros(Float64,nKnots,4) - for i = 1:nKnots - currentLine = split(readline(f)) - for j = 1:4 - splineDataArray[i,j] = parse(Float64,currentLine[j]) - end - end - spline = newSplineCurve(name, nKnots, splineDataArray) - end - return spline -end -""" - duplicateCurve(crv::Dict{String,Any}, newName::String) - -Duplicate the given curve giving it the new name. -""" -function duplicateCurve(crv::Dict{String,Any}, newName::String) - disableNotifications() - disableUndo() - - duplicate = deepcopy(crv) - setCurveName!(duplicate,newName) - - enableNotifications() - enableUndo() - return duplicate -end -""" - setCurveName!(curveDict, name) - -Set the name of the curve represented by curveDict. -""" -function setCurveName!(crv::Dict{String,Any}, name::String) - if haskey(crv,"name") - oldName = crv["name"] - registerWithUndoManager(crv,setCurveName!, (oldName,), "Set Curve Name") - postNotificationWithName(crv,"CURVE_DID_CHANGE_NAME_NOTIFICATION",(oldName,)) - end - crv["name"] = name -end -""" - getCurveName(crv::Dict{String,Any}) -""" -function getCurveName(crv::Dict{String,Any}) - return crv["name"] -end -""" - getCurveType(crv::Dic{String,Any}) - - Get the type of the curve, `END_POINTSLINE_CURVE`, `PARAMETRIC_EQUATION_CURVE`, - `SPLINE_CURVE`, or `CIRCULAR_ARC` as a string. -""" -function getCurveType(crv::Dict{String,Any}) - return crv["TYPE"] -end -""" - setXEqn!(parametricEquationCurve, eqn) - -For a parametric equation, set the x-equation. -""" -function setXEqn!(crv::Dict{String,Any}, eqn::String) - if haskey(crv,"xEqn") - oldEqn = crv["xEqn"] - registerWithUndoManager(crv,setXEqn!, (eqn,), "Set X Equation") - end - crv["xEqn"] = eqn - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getXEqn(crv::Dict{String,Any}) -""" -function getXEqn(crv::Dict{String,Any}) - if(haskey(crv,"xEqn")) - return crv["xEqn"] - end - return nothing -end -""" - setYEqn!(parametricEquationCurve, eqn) - -For a parametric equation, set the y-equation. -""" -function setYEqn!(crv::Dict{String,Any}, eqn::String) - if haskey(crv,"yEqn") - oldEqn = crv["yEqn"] - registerWithUndoManager(crv,setYEqn!, (eqn,), "Set Y Equation") - end - crv["yEqn"] = eqn - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getYEqn(crv::Dict{String,Any}) -""" -function getYEqn(crv::Dict{String,Any}) - if(haskey(crv,"yEqn")) - return crv["yEqn"] - end - return nothing -end -""" - setZEqn!(parametricEquationCurve, eqn) - -For a parametric equation, set the zEqn-equation. -""" -function setZEqn!(crv::Dict{String,Any}, eqn::String) - if haskey(crv,"zEqn") - oldEqn = crv["zEqn"] - registerWithUndoManager(crv,setZEqn!, (eqn,), "Set Z Equation") - end - crv["zEqn"] = eqn - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getZEqn(crv::Dict{String,Any}) -""" -function getZEqn(crv::Dict{String,Any}) - if(haskey(crv,"zEqn")) - return crv["zEqn"] - end - return nothing -end -""" - setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - -Set the start point for a line curve. -""" -function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) - key = "xStart" - if haskey(crv,key) - oldPt = crv[key] - registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") - end - crv[key] = pStr - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) - crv["xStart"] = pointAsString - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getStartPoint(crv::Dict{String,Any}, point::Array{Float64}) - -Get the start point for a line curve as an array -""" -function getStartPoint(crv::Dict{String,Any}) - return realArrayForKeyFromDictionary("xStart",crv) -end -""" - setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - -Set the end point for a line curve. -""" -function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) - key = "xEnd" - if haskey(crv,key) - oldPt = crv[key] - registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") - end - crv[key] = pStr - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) - crv["xEnd"] = pointAsString - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getEndPoint(crv::Dict{String,Any}, point::Array{Float64}) - -Get the end point for a line curve as an array. -""" -function getEndPoint(crv::Dict{String,Any}) - return realArrayForKeyFromDictionary("xEnd",crv) -end -""" - setArcUnits(crv::Dict{String,Any}, units::String) - -Set the units for the start and end angles of a circular arc curve. -""" -function setArcUnits!(arc::Dict{String,Any}, units::String) - if units == "degrees" || units == "radians" - key = "units" - if haskey(arc,key) - oldUnits = arc[key] - registerWithUndoManager(arc,setArcUnits!, (oldUnits,), "Set Arc Units") - end - arc[key] = units - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) - else - println("Units must either be `degrees` or `radians`. Try setting `units` again.") - end -end -""" - getArcUnits(crv::Dict{String,Any}, units::String) - -Get the units for the start and end angles of a circular arc curve. -""" -function getArcUnits!(arc::Dict{String,Any}) - return arc["units"] -end -""" - setArcCenter!(crv::Dict{String,Any}, point::Array{Float64}) - -Set the center of a circular arc. -""" -function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - key = "center" - if haskey(arc,key) - oldVal = arc[key] - registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") - end - - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) - arc[key] = pStr - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) - arc["center"] = pointAsString - postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getArcCenter(crv::Dict{String,Any}, point::Array{Float64}) - -Get the center of a circular arc as an array -""" -function getArcCenter(arc::Dict{String,Any}) - return realArrayForKeyFromDictionary("center",arc) -end -""" - setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - - """ -function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - key = "start angle" - if haskey(arc,key) - oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcStartAngle!, (oldVal,), "Set Arc Start Angle") - end - arc[key] = string(angle) - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getArcStartAngle(arc::Dict{String,Any}, angle::Float64) - - """ -function getArcStartAngle(arc::Dict{String,Any}) - return parse(Float64,arc["start angle"]) -end -""" - setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - - """ -function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - key = "end angle" - if haskey(arc,key) - oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcEndAngle!, (oldVal,), "Set Arc Start Angle") - end - arc[key] = string(angle) - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getArcEndAngle(arc::Dict{String,Any}, angle::Float64) - - """ -function getArcEndAngle(arc::Dict{String,Any}) - return parse(Float64,arc["end angle"]) -end -""" - setArcRadius!(arc::Dict{String,Any}, radius::Float64) - - """ -function setArcRadius!(arc::Dict{String,Any}, radius::Float64) - key = "radius" - if haskey(arc,key) - oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcRadius!, (oldVal,), "Set Arc Radius") - end - arc[key] = string(radius) - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getArcRadius(arc::Dict{String,Any}, radius::Float64) - -""" -function getArcRadius(arc::Dict{String,Any}) - return parse(Float64,arc["radius"]) -end -""" - setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) -""" -function setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) - key = "nKnots" - if haskey(spline,key) - oldVal = parse(Int,spline[key]) - registerWithUndoManager(spline,setSplineNKnots!, (oldVal,), "Set Spline Knots") - end - spline["nKnots"] = string(nKnots) - postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getSplineNKnots(spline::Dict{String,Any}) -""" -function getSplineNKnots(spline::Dict{String,Any}) - return parse(Int,spline["nKnots"]) -end -""" - setSplinePoints!(spline::Dict{String,Any},points::Array{Float64,4}) -""" -function setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) - key = "SPLINE_DATA" - if haskey(spline,key) - registerWithUndoManager(spline,setSplinePoints!, (spline["SPLINE_DATA"],), "Set Spline Points") - end - spline["SPLINE_DATA"] = points - postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - getSplinePoints(spline::Dict{String,Any}) -""" -function getSplinePoints(spline::Dict{String,Any}) - return spline["SPLINE_DATA"] -end diff --git a/HQMTool/Source/Project/Generics.jl b/HQMTool/Source/Project/Generics.jl deleted file mode 100644 index c8976072..00000000 --- a/HQMTool/Source/Project/Generics.jl +++ /dev/null @@ -1,164 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -# -# Creating curves -# -""" - new(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - -Create a new parametric equation curve. -""" -function new(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - return newParametricEquationCurve(name, xEqn, yEqn, zEqn) -end - -""" - new(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - -Create a new line defined by its end points. -""" -function new(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - return newEndPointsLineCurve(name, xStart, xEnd) -end - -""" - new(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String) - -Create a new circular arc. -""" -function new(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String = "degrees") - return newCircularArcCurve(name,center,radius,startAngle,endAngle,units) -end - -""" - new(name::String, dataFile::String) - -Create a spline curve from the contents of a data file. -""" -function new(name::String, dataFile::String) - return newSplineCurve(name, dataFile) -end - -""" - new(name::String, nKnots::Int, data::Matrix{Float64}) - -Create a spline curve from an array of knots -""" -function new(name::String, nKnots::Int, data::Matrix{Float64}) - return newSplineCurve(name, nKnots, data) -end -# -# Adding curves to a model -# -""" - add!(proj::Project, obj::Dict{String,Any}) - -Add a curve to the outer boundary or a refinement reion to -the project -""" -function add!(proj::Project, obj::Dict{String,Any}) - if obj["TYPE"] == "REFINEMENT_CENTER" || obj["TYPE"] == "REFINEMENT_LINE" - addRefinementRegion!(proj, obj) - else - addCurveToOuterBoundary!(proj, obj) - end -end - -""" - add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - -Add a curve to the inner boundary named `boundaryName`. -""" -function add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - addCurveToInnerBoundary!(proj, crv, boundaryName) -end - -""" -get(proj::Project, curveName::String) - -Get the curve with name `curveName` from the outer boundary. -""" -function get(proj::Project, curveName::String) - return getOuterBoundaryCurveWithName(proj, curveName) -end - -""" - get(proj::Project, curveName::String, boundaryName::String) - -Get the curve named `curveName` from the inner boundary named `boundaryName` -""" -function get(proj::Project, curveName::String, boundaryName::String) - return getInnerBoundaryCurve(proj, curveName, boundaryName) -end - -""" - getInnerBoundary(proj::Project, name::String) - -Get the chain of curves from the inner boundary with name `name`. -""" -function getInnerBoundary(proj::Project, name::String) - return getInnerBoundaryChainWithName(proj, name) -end - -""" - remove!(proj::Project, curveName::String) - -Delete the curve named curveName from the outer boundary -""" -function remove!(proj::Project, curveName::String) - removeOuterBoundaryCurveWithName!(proj, curveName) -end - -""" - remove!(proj::Project, curveName::String, innerBoundaryName::String) - -Delete the curve named curveName from the inner boundary named innerBoundaryName -""" -function remove!(proj::Project, curveName::String, innerBoundaryName::String) - removeInnerBoundaryCurve!(proj, curveName, innerBoundaryName) -end - diff --git a/HQMTool/Source/Project/ModelAPI.jl b/HQMTool/Source/Project/ModelAPI.jl deleted file mode 100644 index 336f70ae..00000000 --- a/HQMTool/Source/Project/ModelAPI.jl +++ /dev/null @@ -1,427 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -include("../Model/Geometry.jl") - -# -# -------------------------------------------------------------------------------------- -# -""" - addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - -Add a curve to the outer boundary. The curves must be added in order counter-clockwise -""" -function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - chain = getOuterBoundaryChainList(proj) -# -# Check if the new curve meets the last one added -# - if !isempty(chain) - lastCurve = last(chain) - if !curvesMeet(lastCurve,crv) - lastName = getCurveName(lastCurve) - newName = getCurveName(crv) - println("the curve $lastName does not meet the previous curve, $newName. Try again.") - return - end - end -# -# Checks out, add to model -# - push!(chain,crv) - crvPoints = curvePoints(crv,defaultPlotPts) - push!(proj.outerBndryPoints, crvPoints) - proj.backgroundGridShouldUpdate = true - - push!(proj.outerBndryNames,crv["name"]) - - enableUndo() - registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") - enableNotifications() - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - removeOuterBoundaryCurveWithName!(proj::Project, name::String) - -Remove the named curve in the outer boundary -""" -function removeOuterBoundaryCurveWithName!(proj::Project, name::String) - lst = getOuterBoundaryChainList(proj) - indx = getChainIndex(lst,name) - if indx > 0 - removeOuterBoundaryCurveAtIndex(proj,indx) # posts undo/notification - proj.backgroundGridShouldUpdate = true - end -end -""" - getOuterBoundaryCurveWithName(proj::Project, name::String) -""" -function getOuterBoundaryCurveWithName(proj::Project, name::String) - lst = getOuterBoundaryChainList(proj) - for crv in lst - if crv["name"] == name - return crv - end - end -end -""" - insertOuterBoundaryCurveAtIndex(proj::Project, crv::Dict{String,Any}, indx::Int) - -Insert a curve at the specified index. -""" -function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) - lst = getOuterBoundaryChainList(proj) - insert!(lst,indx,crv) - insert!(proj.outerBndryPoints,indx,curvePoints(crv,defaultPlotPts)) - insert!(proj.outerBndryNames,indx,crv["name"]) - proj.backgroundGridShouldUpdate = true - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) -end - -function removeOuterBoundaryCurveAtIndex(proj::Project, indx::Int) - lst = getOuterBoundaryChainList(proj) - crv = lst[indx] - deleteat!(lst,indx) - deleteat!(proj.outerBndryNames,indx) - deleteat!(proj.outerBndryPoints,indx) - proj.backgroundGridShouldUpdate = true - enableNotifications() - enableUndo() - registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Add Curve") - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - addOuterBoundary!(proj::Project) - -Add an empty outer boundary to the project. There can be only one. -""" -function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) - model = getModelDict(proj) - model["OUTER_BOUNDARY"] = outerBoundary - registerWithUndoManager(proj,removeOuterboundary!, (nothing,), "Add Outer Boundary") -end -""" - removeOuterboundary!(proj::Project) - -Remove the outer boundary curve if it exists. -""" -function removeOuterboundary!(proj::Project) - modelDict = getModelDict(proj) - if haskey(modelDict,"OUTER_BOUNDARY") - ob = modelDict["OUTER_BOUNDARY"] - enableUndo() - registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") - delete!(modelDict,"OUTER_BOUNDARY") - proj.outerBndryPoints = Any[] - proj.outerBndryNames = String[] - proj.backgroundGridShouldUpdate = true - enableNotifications() - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) - end -end - -function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) - modelDict = getModelDict(proj) - modelDict["OUTER_BOUNDARY"] = obDict -end -# -# -------------------------------------------------------------------------------------- -# -""" - getOuterBoundary(proj::Project) - -Get the array of outer boundary curves. -""" -function getOuterBoundaryChainList(proj::Project) - outerBndryDict = getDictInModelDictNamed(proj,"OUTER_BOUNDARY") - if haskey(outerBndryDict,"LIST") - lst = outerBndryDict["LIST"] - return lst - else - lst = Dict{String,Any}[] - outerBndryDict["LIST"] = lst - return lst - end -end -# -# -------------------------------------------------------------------------------------- -# INNER BOUNDARY FUNCTIONS -# -------------------------------------------------------------------------------------- -# -""" - addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - -Add a curve to the inner boundary with name `boundaryName`. If an inner boundary of that name -does not exist, one is created. -""" -function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - - i, chain = getInnerBoundaryChainWithName(proj,boundaryName) - curveList = chain["LIST"] -# -# Check if the new curve meets the last one added -# - if !isempty(curveList) - lastCurve = last(curveList) - if !curvesMeet(lastCurve,crv) - lastName = getCurveName(lastCurve) - newName = getCurveName(crv) - println("the curve $lastName does not meet the previous curve, $newName. Try again.") - return - end - end -# -# Checks out, add to model -# - push!(curveList,crv) - - if i > length(proj.innerBoundaryPoints) # New inner boundary chain - a = [] - push!(a,curvePoints(crv,defaultPlotPts)) - push!(proj.innerBoundaryPoints,a) - else - a = proj.innerBoundaryPoints[i] - push!(a,curvePoints(crv,defaultPlotPts)) - end - push!(proj.innerBoundaryNames[i],crv["name"]) - proj.backgroundGridShouldUpdate = true - registerWithUndoManager(proj,removeInnerBoundaryCurve!, - (crv["name"],boundaryName), - "Add Inner Boundary Curve") - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) -end -""" - removeInnerBoundaryCurve!(proj::Project, name::String) - -Remove the named curve in the outer boundary -""" -function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - i, chain = getInnerBoundaryChainWithName(proj,chainName) - lst = chain["LIST"] - if isempty(lst) - println("No curve ", name, " in boundary ", chainName) #TODO Replace with error() - return - end - indx = getChainIndex(lst,name) - removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) -end - -function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, - indx::Int, boundaryName::String) - i, chain = getInnerBoundaryChainWithName(proj,boundaryName) - lst = chain["LIST"] - insert!(lst,indx,crv) - innerBoundaryPoints = proj.innerBoundaryPoints[i] - insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) - insert!(proj.innerBoundaryNames[i],indx,crv["name"]) - proj.backgroundGridShouldUpdate = true - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) -end - -function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) - i, chain = getInnerBoundaryChainWithName(proj,chainName) - lst = chain["LIST"] - if indx > 0 - crv = lst[indx] - deleteat!(lst,indx) - deleteat!(proj.innerBoundaryNames[i],indx) - deleteat!(proj.innerBoundaryPoints[i],indx) - registerWithUndoManager(proj,insertInnerBoundaryCurveAtIndex!, - (crv,indx,chainName), - "Remove Inner Boundary Curve") - if isempty(lst) - ibChains = getAllInnerBoundaries(proj) - deleteat!(ibChains,i) - deleteat!(proj.innerBoundaryChainNames,i) - deleteat!(proj.innerBoundaryPoints,i) - end - proj.backgroundGridShouldUpdate = true - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) - end -end -""" - removeInnerBoundary!(proj::Project, chainName::String) - -Remove an entire inner boundary -""" -function removeInnerBoundary!(proj::Project, chainName::String) - i,crv = getInnerBoundaryChainWithName(p,chainName) - deleteat!(proj.innerBoundaryChainNames,i) - deleteat!(proj.innerBoundaryPoints,i) - ibChains = getAllInnerBoundaries(proj) - deleteat!(ibChains,i) -end -# -# -------------------------------------------------------------------------------------- -# -""" - addInnerBoundaryWithName!(proj::Project,name::String) - -Create a new empty inner boundary with the given name. -""" -function addInnerBoundaryWithName!(proj::Project,name::String) -# -# Create a new chain -# - bndryChain = Dict{String,Any}() - bndryChain["name"] = name - bndryChain["TYPE"] = "CHAIN" - bndryCurves = Dict{String,Any}[] - bndryChain["LIST"] = bndryCurves - - innerBoundariesList = getAllInnerBoundaries(proj) - push!(innerBoundariesList,bndryChain) -# -# Prepare for plotting -# - push!(proj.innerBoundaryChainNames,name) - componentNames = String[] - push!(proj.innerBoundaryNames,componentNames) - - return bndryChain -end -# -#---------------------------------------------------------------------------------------- -# -function getChainIndex(chain::Vector{Dict{String, Any}},name) - for (i,dict) in enumerate(chain) - if dict["name"] == name - return i - end - end - return 0 -end -""" - getAllInnerBoundaries(proj::Project) - -Returns an array of the inner boundaries -""" -# -# -------------------------------------------------------------------------------------- -# -function getAllInnerBoundaries(proj::Project) - innerBndryDict = getDictInModelDictNamed(proj,"INNER_BOUNDARIES") - if haskey(innerBndryDict,"LIST") - lst = innerBndryDict["LIST"] - return lst - else - lst = [] - innerBndryDict["LIST"] = lst - return lst - end - return nothing -end -# -# -------------------------------------------------------------------------------------- -# -""" - getInnerBoundaryWithName(proj::Project, name::String) - -Get the inner boundary CHAIN with the given name. If one does not exist, it -is created. -""" -function getInnerBoundaryChainWithName(proj::Project, name::String) - lst = getAllInnerBoundaries(proj::Project) - # - # See if there is an inner boundary with that name - # - l = length(lst) - i = 1 - if l > 0 - for chain in lst - bCurveName = chain["name"] - if bCurveName == name - return i, chain - i = i + 1 - end - end - end - # - # If not, create one - # - chain = addInnerBoundaryWithName!(proj,name) - return l+1, chain -end -""" - -""" -function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - i, chain = getInnerBoundaryChainWithName(proj,boundaryName) - lst = chain["LIST"] - for crv in lst - if crv["name"] == curveName - return crv - end - end - return nothing -end -""" - innerBoundaryIndices(proj::Project, curveName::String) - -Returns (curveIndex,chainIndex) for the location of the curve named `curveName` -in it's inner boundary chain. -""" -function innerBoundaryIndices(proj::Project, curveName::String) -# -# For each inner boundary curve chain -# - chains = getAllInnerBoundaries(proj) - for (j,chain) in enumerate(chains) - crvList = chain["LIST"] - for (i,crv) in enumerate(crvList) - if crv["name"] == curveName - return i,j - end - end - end - return (0,0) -end -# -# -------------------------------------------------------------------------------------- -# -function getModelDict(proj::Project) - if haskey(proj.projectDictionary,"MODEL") - return proj.projectDictionary["MODEL"] - else - modelDict = Dict{String,Any}() - proj.projectDictionary["MODEL"] = modelDict - modelDict["TYPE"] = "MODEL" - return modelDict - end -end - -function getDictInModelDictNamed(proj::Project,name::String) - modelDict = getModelDict(proj) - - if haskey(modelDict,name) - return modelDict[name] - else - d = Dict{String,Any}() - modelDict[name] = d - d["TYPE"] = name - return d - end -end diff --git a/HQMTool/Source/Project/Project.jl b/HQMTool/Source/Project/Project.jl deleted file mode 100644 index 98fd4428..00000000 --- a/HQMTool/Source/Project/Project.jl +++ /dev/null @@ -1,409 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# -#= - The Project is the controller in an MVC paradigm. It manages the model, - stored in the projectDictionary, and plotting data, and responds to enableNotifications - of changes. -=# -mutable struct Project - name::String - projectDirectory:: String - projectDictionary::Dict{String,Any} - plt::Any #For the plot - plotOptions::Int # = combinations of MODEL, GRID, MESH -# -# For drawing -# - outerBndryPoints ::Array{Any} # CHAIN - outerBndryNames ::Array{String} - innerBoundaryPoints ::Array{Any} # Array of CHAINs - innerBoundaryNames ::Array{Any} # Array of CHAINs of names - innerBoundaryChainNames::Array{String} # Array of the names of the CHAINs - refinementRegionPoints ::Array{Array{Float64,2}} # Array of Array of points - refinementRegionNames ::Array{String} - refinementRegionLoc ::Array{Array{Float64}} # Center point of a refinement region - bounds ::Array{Float64} - userBounds ::Array{Float64} - xGrid ::Array{Float64} - yGrid ::Array{Float64} - xMesh ::Array{Float64} - yMesh ::Array{Float64} - backgroundGridShouldUpdate::Bool - meshShouldUpdate ::Bool -end - -defaultPlotPts = 50 -meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) -plotFileFormats = Set(["sem", "skeleton"]) -smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) -statusValues = Set(["ON", "OFF"]) -refinementTypes = Set(["smooth", "sharp"]) - -include("./ControlInputAPI.jl") -include("./BackgroundGridAPI.jl") -include("./ModelAPI.jl") -include("./RefinementRegionsAPI.jl") -include("./RunParametersAPI.jl") -include("./SmootherAPI.jl") - -""" - openProject(fileName::String, folder::String) - -Open existing project described in the control File. - - folder = folder the control file is in - fileNmae = the name of the file -""" -function openProject(fileName::String, folder::String) - - controlFile = joinpath(folder,fileName) - splitName = split(fileName,".") - - controlDict = ImportControlFile(controlFile) - - s = string(splitName[1]) # This is dumb - proj = newProject(s,folder) -# -# Overwrite defaults -# - proj.projectDictionary = controlDict - - assemblePlotArrays(proj) - clearUndoRedo() - - return proj -end -""" - saveProject(proj::Project) - - proj = Project to be saved -Save a project dictionary to the file path specified when the project was created. -""" -function saveProject(proj::Project) - getfolder = mkpath(proj.projectDirectory) - fileName = joinpath(proj.projectDirectory,proj.name)*".control" - WriteControlFile(proj.projectDictionary,fileName) -end -""" - newProject(name::String, folder::String) - -Create a new project with the given name. That name will be used -for the mesh and plot files in the specified folder. -""" -function newProject(name::String, folder::String) - ibChainPoints = Any[] - ibChainNames = String[] - ibNames = Any[] - obNames = String[] - obPnts = Any[] - projectDict = Dict{String,Any}() - plt = nothing - undoStack = Any[] - redoStack = Any[] - bounds = emptyBounds() # top, left, bottom, right - userBounds = emptyBounds() - xGrid = Float64[] - yGrid = Float64[] - xMesh = Float64[] - yMesh = Float64[] - refinementRegionPts = Array{Array{Float64,2}}[] - refinementRegionNames = Array{String}[] - refinementRegionLocs = Array{Array{Float64}}[] - plotOptions = 0 -# - proj = Project(name, folder, projectDict, plt, plotOptions, obPnts, obNames, - ibChainPoints,ibNames, ibChainNames, - refinementRegionPts,refinementRegionNames, refinementRegionLocs, - bounds, userBounds, xGrid, yGrid, xMesh, yMesh, - true, false) - - addObserver(proj,"CURVE_DID_CHANGE_NOTIFICATION",curveDidChange) - addObserver(proj,"MODEL_DID_CHANGE_NOTIFICATION",modelDidChange) - addObserver(proj,"BGRID_DID_CHANGE_NOTIFICATION",backgroundGridDidChange) - addObserver(proj,"MESH_WAS_GENERATED_NOTIFICATION",meshWasGenerated) - addObserver(proj,"MESH_WAS_DELETED_NOTIFICATION",meshWasDeleted) - addObserver(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",refinementWasAdded) - addObserver(proj,"REFINEMENT_WAS_CHANGED_NOTIFICATION",refinementDidChange) - enableNotifications() -# -# Set some default values -# - addRunParameters!(proj) - addSpringSmoother!(proj) - enableUndo() - return proj -end -""" -hasBackgroundGrid(proj::Project) - -Tests to see if the project has a backgroundGrid dictionary defined. -""" -function hasBackgroundGrid(proj::Project) - controlDict = getControlDict(proj) - if haskey(controlDict,"BACKGROUND_GRID") - return true - else - return false - end -end - -function assemblePlotArrays(proj::Project) - - empty!(proj.outerBndryPoints) - empty!(proj.outerBndryNames) - empty!(proj.innerBoundaryChainNames) - empty!(proj.innerBoundaryPoints) - empty!(proj.innerBoundaryNames) - empty!(proj.xGrid) - empty!(proj.yGrid) - - bounds = emptyBounds() - - modelDict = getModelDict(proj) - - if haskey(modelDict,"OUTER_BOUNDARY") - outerBoundary = modelDict["OUTER_BOUNDARY"] - obChain = outerBoundary["LIST"] - proj.outerBndryPoints = chainPoints(obChain,defaultPlotPts) - - chB = chainBounds(proj.outerBndryPoints) - bounds = bboxUnion(bounds,chB) - - for crv in obChain - push!(proj.outerBndryNames,crv["name"]) - end - end - - if haskey(modelDict,"INNER_BOUNDARIES") - innerBoundaries = modelDict["INNER_BOUNDARIES"] - innerBoundaryList = innerBoundaries["LIST"] #LIST of CHAINS - for d in innerBoundaryList - push!(proj.innerBoundaryChainNames, d["name"]) - ibChain = d["LIST"] - ibPnts = chainPoints(ibChain,defaultPlotPts) - push!(proj.innerBoundaryPoints,ibPnts) - chB = chainBounds(ibPnts) - bounds = bboxUnion(bounds,chB) - names = String[] - for crv in ibChain - push!(names,crv["name"]) - end - push!(proj.innerBoundaryNames,names) - end - end - - controlDict = getControlDict(proj) - - if haskey(controlDict,"REFINEMENT_REGIONS") - refinementBlock = controlDict["REFINEMENT_REGIONS"] - refinementsList = refinementBlock["LIST"] - for ref in refinementsList - addRefinementRegionPoints!(proj,ref) - end - end - proj.bounds = bounds -end - -function projectBounds(proj::Project) - bounds = emptyBounds() - - if !isempty(proj.outerBndryPoints) - chB = chainBounds(proj.outerBndryPoints) - bounds = bboxUnion(bounds,chB) - end - - if !isempty(proj.innerBoundaryPoints) - for i = 1:length(proj.innerBoundaryPoints) - ibPnts = proj.innerBoundaryPoints[i] - chB = chainBounds(ibPnts) - bounds = bboxUnion(bounds,chB) - end - end - return bounds -end - -function projectGrid(proj::Project) - - controlDict = proj.projectDictionary["CONTROL_INPUT"] - - if haskey(controlDict,"BACKGROUND_GRID") - bgDict = controlDict["BACKGROUND_GRID"] - - if haskey(bgDict,"dx") - N = intArrayForKeyFromDictionary("N", bgDict) - x0 = realArrayForKeyFromDictionary("x0",bgDict) - left = x0[1] - bottom = x0[2] - xGrid = zeros(Float64, N[1]+1) - yGrid = zeros(Float64, N[2]+1) - dx = realArrayForKeyFromDictionary("dx", bgDict) - for i = 1:N[1]+1 - xGrid[i] = left + (i-1)*dx[1] - end - for j = 1:N[2]+1 - yGrid[j] = bottom + (j-1)*dx[2] - end - else - dx = realArrayForKeyFromDictionary("background grid size", bgDict) - bounds = proj.bounds - - width = bounds[RIGHT] - bounds[LEFT] - height = bounds[TOP] - bounds[BOTTOM] - - Nx = Int(round(width/dx[1])) + 3 # Want the model inside the grid - Ny = Int(round(height/dx[2])) + 3 - - xGrid = zeros(Float64, Nx) - yGrid = zeros(Float64, Ny) - - for i = 1:Nx - xGrid[i] = bounds[LEFT] + (i-2)*dx[1] # Arrays start at 1, ugh. - end - for j = 1:Ny - yGrid[j] = bounds[BOTTOM] + (j-2)*dx[2] - end - end - end - - return xGrid, yGrid -end -# -# NOTIFICATION ACTIONS -# -function curveDidChange(proj::Project,crv::Dict{String,Any}) - curveName = getCurveName(crv) -# -# Find the curve location: See if the curve is in the outer boundary -# - for (i,s) in enumerate(proj.outerBndryNames) - if s == curveName - proj.outerBndryPoints[i] = curvePoints(crv,defaultPlotPts) - if !isnothing(proj.plt) - options = proj.plotOptions - updatePlot!(proj, options) - end - return nothing - end - end -# -# Otherwise, see if it is an inner boundary -# - crvNumber, bndryNumber = innerBoundaryIndices(proj,curveName) - if crvNumber == 0 || bndryNumber == 0 - return nothing - end - innerBoundaryPoints = proj.innerBoundaryPoints[bndryNumber] - innerBoundaryPoints[crvNumber] = curvePoints(crv,defaultPlotPts) - proj.backgroundGridShouldUpdate = true - - if !isnothing(proj.plt) - options = proj.plotOptions - updatePlot!(proj, options) - end - return nothing -end - -function modelDidChange(proj::Project, sender::Project) - - if proj === sender && !isnothing(proj.plt) - options = proj.plotOptions - if (options & MODEL) == 0 - options = options + MODEL - end - updatePlot!(proj, options) - end -end - -function backgroundGridDidChange(proj::Project, sender::Project) - if proj === sender && !isnothing(proj.plt) - proj.backgroundGridShouldUpdate = true - options = proj.plotOptions - if (options & GRID) == 0 - options = options + GRID - end - updatePlot!(proj, options) - end -end - -function refinementWasAdded(proj::Project, sender::Project) - if proj === sender && !isnothing(proj.plt) - options = proj.plotOptions - if (options & REFINEMENTS) == 0 - options = options + REFINEMENTS - end - updatePlot!(proj, options) - end -end - -function refinementDidChange(proj::Project, sender::Dict{String,Any}) - regionName = sender["name"] - lst = getAllRefinementRegions(proj) - indx = 0 - for (i,r) in enumerate(lst) - if r["name"] == regionName - indx = i - break - end - end - - if indx > 0 - x = refinementRegionPoints(sender) - proj.refinementRegionPoints[indx] = x - proj.refinementRegionNames[indx] = sender["name"] - center = refinementRegionCenter(sender) - proj.refinementRegionLoc[indx] = center - - if !isnothing(proj.plt) - options = proj.plotOptions - if (options & REFINEMENTS) == 0 - options = options + REFINEMENTS - end - updatePlot!(proj, options) - end - else - println("Refinement region with name $regionName not found.") - end -end - -function meshWasGenerated(proj::Project, sender::Project) - if proj === sender && !isnothing(proj.plt) - options = proj.plotOptions - options = (MODEL & options) + MESH - proj.meshShouldUpdate = true - updatePlot!(proj, options) - end -end - -function meshWasDeleted(proj::Project, sender::Project) - if proj === sender && !isnothing(proj.plt) - options = proj.plotOptions - if (MESH & options) > 0 - options = options - MESH - end - proj.meshShouldUpdate = false - updatePlot!(proj, options) - end -end diff --git a/HQMTool/Source/Project/RefinementRegionsAPI.jl b/HQMTool/Source/Project/RefinementRegionsAPI.jl deleted file mode 100644 index 1c439034..00000000 --- a/HQMTool/Source/Project/RefinementRegionsAPI.jl +++ /dev/null @@ -1,476 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -""" -newRefinementCenter(type, - center, meshSize, - width ) - -Create refinement center of `type` "smooth" or "sharp" centered at `center = [x,y,z]`` -with a mesh size `meshSize` spread over a radius `width`. -""" -function newRefinementCenter(name::String, type::String, - x0::Array{Float64}, h::Float64, - w::Float64 ) - disableUndo() - disableNotifications() - centerDict = Dict{String,Any}() - centerDict["TYPE"] = "REFINEMENT_CENTER" - setRefinementType!(centerDict,type) - setRefinementLocation!(centerDict,x0) - setRefinementGridSize!(centerDict,h) - setRefinementWidth!(centerDict,w) - setRefinementName!(centerDict,name) - enableNotifications() - enableUndo() - return centerDict -end -""" - addRefinementRegion!(proj::Project,r::Dict{String,Any}) - -Add the refinement region to the project -""" -function addRefinementRegion!(proj::Project,r::Dict{String,Any}) - lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") - push!(lst,r) - addRefinementRegionPoints!(proj,r) - enableUndo() - registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Add Refinement Region") - enableNotifications() - postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) -end -""" - addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) - -Compute and add to the project the plotting points for the refinement region -""" -function addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) - - x = refinementRegionPoints(r) - push!(proj.refinementRegionPoints,x) - push!(proj.refinementRegionNames, r["name"]) - center = refinementRegionCenter(r) - push!(proj.refinementRegionLoc,center) -end -""" - refinementRegionPoints(r::Dict{String,Any}) - - Returns Array{Float64,2} being the plotting points of a refinement region -""" -function refinementRegionPoints(r::Dict{String,Any}) - - if r["TYPE"] == "REFINEMENT_CENTER" - center = getRefinementLocation(r) - radius = getRefinementWidth(r) - - N = defaultPlotPts - x = zeros(Float64,N+1,2) - t = zeros(Float64,N+1) - for i = 1:N+1 - t[i] = (i-1)/N - end - arcCurvePoints(center,radius,0.0,360.0,"degrees",t,x) - return x - else - xStart = realArrayForKeyFromDictionary("x0",r) - xEnd = realArrayForKeyFromDictionary("x1",r) - dx = xEnd - xStart - l = sqrt(dx[1]^2 + dx[2]^2) - w = realForKeyFromDictionary("w",r) - v = [-dx[2]/l,dx[1]/l] - x1 = xStart[1:2] + w*v - x2 = xEnd[1:2] + w*v - v = [dx[2]/l,-dx[1]/l] - x3 = xEnd[1:2] + w*v - x4 = xStart[1:2] + w*v - x = zeros(Float64,5,2) - x[1,:] = x1 - x[2,:] = x2 - x[3,:] = x3 - x[4,:] = x4 - x[5,:] = x1 - return x - end - -end -""" - refinementRegionCenter(r::Dict{String,Any}) - -Get, or compute, the center of the given refinement region. -""" -function refinementRegionCenter(r::Dict{String,Any}) - if r["TYPE"] == "REFINEMENT_CENTER" - center = getRefinementLocation(r) - return center[1:2] - else - xStart = realArrayForKeyFromDictionary("x0",r) - xEnd = realArrayForKeyFromDictionary("x1",r) - xAvg = 0.5*(xStart + xEnd) - return xAvg[1:2] - end -end -""" - removeRefinementRegion!(proj::Project, name::String) - -Delete the named refinement region. -""" -function removeRefinementRegion!(proj::Project, name::String) - i,r = getRefinementRegion(proj,name) - lst = getAllRefinementRegions(proj) - deleteat!(lst,i) - deleteat!(proj.refinementRegionLoc,i) - deleteat!(proj.refinementRegionNames,i) - deleteat!(proj.refinementRegionPoints,i) - registerWithUndoManager(proj,insertRefinementRegion!, (r,i,), "Remove Refinement Region") - enableNotifications() - postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) -end -""" - insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) - -Used by undo() -""" -function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) - lst = getAllRefinementRegions(proj) - registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Set Insert Refinement Region") - insert!(lst,indx,r) - x = refinementRegionPoints(r) - insert!(proj.refinementRegionPoints,indx,x) - center = refinementRegionCenter(r) - insert!(proj.refinementRegionLoc,indx,center) - insert!(proj.refinementRegionNames,indx,r["name"]) - postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) -end -# -# -------------------------------------------------------------------------------------- -# -""" - newRefinementLine(type, - start, end, - meshSize, - width ) - -Create refinement line of type "smooth" or "sharp" between `start` = [x,y,z] and `end` = [x,y,z] -with a mesh size `meshSize` spread over a width `width`. -""" -function newRefinementLine(name::String, type::String, - x0::Array{Float64}, x1::Array{Float64}, - h::Float64, - w::Float64 ) - disableUndo() - disableNotifications() - lineDict = Dict{String,Any}() - lineDict["TYPE"] = "REFINEMENT_LINE" - setRefinementType(lineDict,type) - setRefinementStart(lineDict,x0) - setRefinementEnd(lineDict,x1) - setRefinementGridSize(lineDict,h) - setRefinementWidth(lineDict,w) - setRefinementName!(lineDict,name) - enableNotifications() - enableUndo() - return lineDict -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementRegion(proj::Project, indx) - -Get the refinement region with index, indx from the project. Returns nothing if -there is none. The return value is a dictionary that represents the refinement region. -""" -function getRefinementRegion(proj::Project, indx::Int) - lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") - if indx > length(lst) - printf("Index %i is larger than the number of refinement regions, %i", indx, length(lst)) - return nothing - end - return lst[indx] -end -# -# -------------------------------------------------------------------------------------- -# -""" - allRefinementRegions(proj::Project) - -Get the list of refinement regions. -""" -function getAllRefinementRegions(proj::Project) - lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") - return lst -end -# -# -------------------------------------------------------------------------------------- -# -""" - (i,r) = getRefinementRegion(project, name) - -Get the refinement region with the given name and its location in the list of refinement regions. -""" -function getRefinementRegion(proj::Project, name::String) - lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") - for (i,r) in enumerate(lst) - if r["name"] == name - return i,r - end - end - println("Refinement region with name %s not found",name) - return nothing -end -# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementType!(refinementRegion, type) - -Set the type, either "smooth" or "sharp" for the given refinement region. -""" -function setRefinementType!(r::Dict{String,Any}, type::String) - if !in(type,refinementTypes) - println("Acceptable refinement types are `smooth` and `sharp`. Try again.") - return - end - - if haskey(r,"type") - oldType = r["type"] - registerWithUndoManager(r,setRefinementType!, (oldType,), "Set Refinement Type") - end - r["type"] = type -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementType(r::Dict{String,Any}) - -Return the type of refinement, either "smooth" or "sharp". `r` is the dictionary that -represents the refinement region. -""" -function getRefinementType(r::Dict{String,Any}) - return r["type"] -end -""" - setRefinementName!(r::Dict{String,Any}, type) - -Set a name for the refinement region.`r` is the dictionary that - represents the refinement region. -""" -function setRefinementName!(r::Dict{String,Any}, name::String) - if haskey(r,"name") - oldName = r["name"] - registerWithUndoManager(r,setRefinementName!, (oldName,), "Set Refinement Name") - end - r["name"] = name - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementName(r::Dict{String,Any}) - -Return name of the refinement. `r` is the dictionary that -represents the refinement region. -""" -function getRefinementName(r::Dict{String,Any}) - return r["name"] -end# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementLocation!(refinementCenter, location) - -Set the location of a refinement center to location = [x,y,z]. -""" -function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") - end - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x0"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) - return nothing -end - -function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") - end - r["x0"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementLocation(r::Dict{String,Any}) - -Return Array{Float64} of the location of the refinement center.`r` is the dictionary that -represents the refinement region. -""" -function getRefinementLocation(r::Dict{String,Any}) - return realArrayForKeyFromDictionary("x0",r) -end -# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementGridSize(r::Dict{String,Any}, h) - -Set the grid size, `h` for the refinement region. `r` is the dictionary that -represents the refinement region. -""" -function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) - if haskey(r,"h") - old = r["h"] - registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") - end - r["h"] = string(h) -end -function setRefinementGridSize!(r::Dict{String,Any}, h::String) - hf = parse(Float64,h) - setRefinementGridSize!(r,hf) -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementGridSize(r::Dict{String,Any}) - -Returns the grid size,h, as Float64. `r` is the dictionary that -represents the refinement region. -""" -function getRefinementGridSize(r::Dict{String,Any}) - return parse(Float64,r["h"]) -end -# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementWidth!(r::Dict{String,Any}, width) - -Set the width of the refinement region. `r` is the dictionary that -represents the refinement region. -""" -function setRefinementWidth!(r::Dict{String,Any},w::Float64) - if haskey(r,"w") - old = r["w"] - registerWithUndoManager(r,setRefinementWidth!, (old,), "Set Refinement Width") - end - r["w"] = string(w) - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) -end -function setRefinementWidth!(r::Dict{String,Any},w::String) - wf = parse(Float64,w) - setRefinementWidth!(r,wf) -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementWidth(r::Dict{String,Any}) - -Returns the region width,w, as Float64. `r` is the dictionary that -represents the refinement region. -""" -function getRefinementWidth(r::Dict{String,Any}) - return parse(Float64,r["w"]) -end -# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementStart!(refinementRegion, location) - -Set the start point location of a refinement line, `location = [x, y, z]`. -""" -function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") - end - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x0"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(r,)) -end -function setRefinementStart!(r::Dict{String,Any}, x0Str::String) - if haskey(r,"x0") - old = r["x0"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") - end - r["x0"] = x0Str -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementStart (r::Dict{String,Any}) - -Return Array{Float64} of the start location of the refinement line. `r` is the dictionary that -represents the refinement region. -""" -function getRefinementStart(r::Dict{String,Any}) - return realArrayForKeyFromDictionary("x0",r) -end -# -# -------------------------------------------------------------------------------------- -# -""" - setRefinementEnd(refinementRegion, location) - -Set the end point location of a refinement line, `location = [x, y, z]`. -""" -function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - if haskey(r,"x1") - old = r["x1"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") - end - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) - r["x1"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) -end -function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) - if haskey(r,"x1") - old = r["x1"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement End") - end - r["x1"] = x0Str - postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) -end -# -# -------------------------------------------------------------------------------------- -# -""" - getRefinementEnd(r::Dict{String,Any}) - -Return Array{Float64} of the end location of the refinement line -""" -function getRefinementEnd(r::Dict{String,Any}) - return realArrayForKeyFromDictionary("x1",r) -end diff --git a/HQMTool/Source/Project/SmootherAPI.jl b/HQMTool/Source/Project/SmootherAPI.jl deleted file mode 100644 index eb046084..00000000 --- a/HQMTool/Source/Project/SmootherAPI.jl +++ /dev/null @@ -1,118 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -""" - addSpringSmoother!(status::String, type::String, nIterations::Int) - - status is either `ON` or `OFF` - type is either `LinearSpring` or `LinearAndCrossbarSpring` - -""" -function addSpringSmoother!(proj::Project,status::String = "ON", - type::String = "LinearAndCrossbarSpring", - nIterations::Int = 25) - if !in(status,statusValues) - println("Acceptable smoother status are `ON` and `OFF`. Try again.") - return - end - if !in(type,smootherTypes) - println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") - return - end - setSmoothingStatus!(proj,status) - setSmoothingType!(proj,type) - setSmoothingIterations!(proj,nIterations) -end -""" - setSmoothingStatus(proj:Project, status::String) - -status is either "ON" or "OFF" -""" -function setSmoothingStatus!(proj::Project, status::String) - if !in(status,statusValues) - println("Acceptable smoother status are `ON` and `OFF`. Try again.") - return - end - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - smDict["smoothing"] = status -end -""" - smoothingStatus(proj::Project) - -Returns whether the smoother will be "ON" or "OFF" -""" -function getSmoothingStatus(proj::Project) - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - return smDict["smoothing"] -end -""" -setSmoothingType!(proj:Project, status::String) - -type is either `LinearSpring` or `LinearAndCrossbarSpring` -""" -function setSmoothingType!(proj::Project, type::String) - if !in(type,smootherTypes) - println("Acceptable smoothers are `LinearSpring` and `LinearAndCrossbarSpring`. Try again.") - return - end - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - smDict["smoothing type"] = type -end -""" - smoothingType(proj::Project) - -Returns either "LinearSpring" or "LinearAndCrossbarSpring" -""" -function getSmoothingType(proj::Project) - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - return smDict["smoothing type"] -end -""" - setSmoothingIterations!((proj::Project, iterations::Int) - -Set the number of iterations to smooth the mesh. -""" -function setSmoothingIterations!(proj::Project, iterations::Int) - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - smDict["number of iterations"] = iterations -end -""" - -""" -function getSmoothingIterations(proj::Project) - smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") - return smDict["number of iterations"] - -end -""" - removeSpringSmoother!(proj::Project) - -Remove the background grid block from the project. -""" -function removeSpringSmoother!(proj::Project) - cDict = getControlDict(proj) - delete!(cDict,"SPRING_SMOOTHER") -end diff --git a/HQMTool/Source/Project/Undo.jl b/HQMTool/Source/Project/Undo.jl deleted file mode 100644 index c14438f3..00000000 --- a/HQMTool/Source/Project/Undo.jl +++ /dev/null @@ -1,142 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -struct UROperation - object::Any - action::Any - data ::Tuple - name ::String -end - -@enum UNDO_OPERATION_TYPE begin - UNDO_USER_OPERATION = 0 - UNDO_OPERATION = 1 - REDO_OPERATION = 2 - UNDO_IGNORE = 3 -end - -#= -TODO: The undo framework currently works globally, within the REPL. It *should* work project-by-project. -To make it project based, undo() would be replaced by undo(project) and an .undoStack -property of the project would replace HQMglobalUndoStack. This is -not a big deal except if multiple projects are open, and muliple objects like curves have been -defined but not added to a project. In interactive mode curves are separate from projects until -added. (The same curve could be added to multiple projects.) So some logic needs to be -figured out before modifying below. If only one project is managed per session, -then this is not a problem. -=# -HQMglobalUndoStack = [] -HQMglobalRedoStack = [] -HQMglobalChangeOP = UNDO_IGNORE - -function undo() - if !isempty(HQMglobalUndoStack) - op = pop!(HQMglobalUndoStack) - f = op.action - d = op.data - obj = op.object - global HQMglobalChangeOP = UNDO_OPERATION - if isnothing(d[1]) - f(obj) - else - f(obj,d...) - end - global HQMglobalChangeOP = UNDO_USER_OPERATION - return "Undo "*op.name - end - return "Empty undo stack. No action performed." -end - -function redo() - if !isempty(HQMglobalRedoStack) - op = pop!(HQMglobalRedoStack) - f = op.action - d = op.data - obj = op.object - global HQMglobalChangeOP = REDO_OPERATION - if isnothing(d[1]) - f(obj) - else - f(obj,d...) - end - global HQMglobalChangeOP = UNDO_USER_OPERATION - return "Redo " * op.name - end - return "Empty redo stack. No action performed." -end - -function registerUndo(obj, action, data::Tuple, name::String) - uOp = UROperation(obj,action,data,name) - push!(HQMglobalUndoStack,uOp) -end - -function registerWithUndoManager(obj, action, oldData::Tuple, name::String) - - if HQMglobalChangeOP == UNDO_USER_OPERATION #User action - registerUndo(obj,action,oldData,name) - elseif HQMglobalChangeOP == UNDO_OPERATION #Undo operation - registerRedo(obj,action,oldData,name) - elseif HQMglobalChangeOP == REDO_OPERATION #Redo operation - registerUndo(obj,action,oldData,name) - else - # UNDO_IGNORE - end -end - -function registerRedo(obj, action, data::Tuple, name::String) - rOp = UROperation(obj,action,data,name) - push!(HQMglobalRedoStack,rOp) -end - -function clearUndoRedo() - empty!(HQMglobalUndoStack) - empty!(HQMglobalRedoStack) -end - -function undoActionName() - if !isempty(HQMglobalUndoStack) - op = last(HQMglobalUndoStack) - return op.name - end - return "No undo action in queue" -end - - -function redoActionName() - if !isempty(HQMglobalRedoStack) - op = last(HQMglobalRedoStack) - return op.name - end - return "No redo action in queue" -end - -function disableUndo() - global HQMglobalChangeOP = UNDO_IGNORE -end - -function enableUndo() - global HQMglobalChangeOP = UNDO_USER_OPERATION -end From 8f839541a39cd2814af44bf451bf620ed9e14fea Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 12:19:41 +0100 Subject: [PATCH 029/164] attempt to properly include HQMTool functionality such that simply using HOHQMesh will give access to everything --- src/HOHQMesh.jl | 122 ++++++++++++++++++++++++++++++++++++++++- src/HQMTool.jl | 140 ------------------------------------------------ 2 files changed, 120 insertions(+), 142 deletions(-) delete mode 100644 src/HQMTool.jl diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 39bdbd7b..23d386a3 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -4,9 +4,12 @@ module HOHQMesh # (standard library packages first, other packages next, all of them sorted alphabetically) using HOHQMesh_jll: HOHQMesh_jll +using Printf using Requires: @require export generate_mesh +export hqmtool_all_features_demo +export hqmtool_ice_cream_cone_verbose_demo, hqmtool_ice_cream_cone_demo function __init__() @@ -128,7 +131,122 @@ Return the path to the directory with some example mesh setups. examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") -# FIXME: Include this in a proper way -# include("HQMTool.jl") +# Include functionality for interactive reading, writing, and plotting of a model for HOHQMesh +include("Viz/VizMesh.jl") +include("Misc/NotificationCenter.jl") +include("Misc/DictionaryOperations.jl") +include("Curves/Spline.jl") +include("ControlFile/ControlFileOperations.jl") +include("Curves/CurveOperations.jl") +include("Project/Project.jl") +include("Project/CurvesAPI.jl") +include("Viz/VizProject.jl") +include("Project/Undo.jl") +include("Mesh/Meshing.jl") +include("Project/Generics.jl") + +# +#---------------- Routines for testing and demonstrating the HQMTool --------------------------------- +# + +function hqmtool_all_features_demo() +# +# Reads in an existing control file, plots the boundary curves and generates +# a mesh. +# + p = openProject("AllFeatures.control", joinpath(@__DIR__, "..", "examples")) + plotProject!(p,MODEL+REFINEMENTS+GRID) + println("Hit any key to continue and generate the mesh") + readline() + generateMesh(p) + return p +end + +function hqmtool_ice_cream_cone_verbose_demo(folder::String) +# +# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# written to `folder`. +# + p = newProject("IceCreamCone",folder) +# +# Outer boundary +# + circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + addCurveToOuterBoundary!(p,circ) +# +# Inner boundary +# + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p,cone1,"IceCreamCone") + addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") + addCurveToInnerBoundary!(p,cone2,"IceCreamCone") +# +# Set some control RunParameters to overwrite the defaults +# + setPolynomialOrder!(p,4) + setPlotFileFormat!(p,"sem") +# +# To mesh, a background grid is needed +# + addBackgroundGrid!(p, [0.5,0.5,0.0]) +# +# Show the model and grid +# + plotProject!(p, MODEL+GRID) +# +# Generate the mesh and plot +# + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + return p +end + +function hqmtool_ice_cream_cone_demo(folder::String) +# +# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# written to `path`. +# + p = newProject("IceCreamCone",folder) +# +# Outer boundary +# + circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + add!(p,circ) +# +# Inner boundary +# + cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) + add!(p,cone1,"IceCreamCone") + add!(p,iceCream,"IceCreamCone") + add!(p,cone2,"IceCreamCone") +# +# To mesh, a background grid is needed +# + addBackgroundGrid!(p, [0.5,0.5,0.0]) +# +# Set alternative file format and corresponding output file names +# + setMeshFileFormat!(p, "ABAQUS") + meshFileFormat = getMeshFileFormat(p) + setFileNames!(p, meshFileFormat) +# +# Show the model and grid +# + plotProject!(p, MODEL+GRID) +# +# Generate the mesh and plot +# + println("Press any key to continue and generate the mesh") + readline() + generateMesh(p) + + return p +end end # module diff --git a/src/HQMTool.jl b/src/HQMTool.jl deleted file mode 100644 index cc5171f6..00000000 --- a/src/HQMTool.jl +++ /dev/null @@ -1,140 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -using Printf -#= - A program for reading, writing and plotting a model for HOHQMesh -=# -include("Viz/VizMesh.jl") -include("Misc/NotificationCenter.jl") -include("Misc/DictionaryOperations.jl") -include("Curves/Spline.jl") -include("ControlFile/ControlFileOperations.jl") -include("Curves/CurveOperations.jl") -include("Project/Project.jl") -include("Project/CurvesAPI.jl") -include("Viz/VizProject.jl") -include("Project/Undo.jl") -include("Mesh/Meshing.jl") -include("Project/Generics.jl") - -# -#---------------- FOR TESTING PURPOSES -------------------------------------- -# - -function runDemo() -#= - Reads in an existing control file, plots the boundary curves and generates - a mesh. -=# - p = openProject("AllFeatures.control", joinpath(@__DIR__, "..", "examples")) - plotProject!(p,MODEL+REFINEMENTS+GRID) - println("Hit any key to continue and generate the mesh") - readline() - generateMesh(p) - return p -end - -function iceCreamConeVerbose(folder::String) -# -# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# written to `folder`. -# - p = newProject("IceCreamCone",folder) -# -# Outer boundary -# - circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - addCurveToOuterBoundary!(p,circ) -# -# Inner boundary -# - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p,cone1,"IceCreamCone") - addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") - addCurveToInnerBoundary!(p,cone2,"IceCreamCone") -# -# Set some control RunParameters to overwrite the defaults -# - setPolynomialOrder!(p,4) - setPlotFileFormat!(p,"sem") -# -# To mesh, a background grid is needed -# - addBackgroundGrid!(p, [0.5,0.5,0.0]) -# -# Show the model and grid -# - plotProject!(p, MODEL+GRID) -# -# Generate the mesh and plot -# - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - - return p -end - -function iceCreamCone(folder::String) -# -# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# written to `path`. -# - p = newProject("IceCreamCone",folder) -# -# Outer boundary -# - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) -# -# Inner boundary -# - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") -# -# To mesh, a background grid is needed -# - addBackgroundGrid!(p, [0.5,0.5,0.0]) -# -# Show the model and grid -# - plotProject!(p, MODEL+GRID) -# -# Generate the mesh and plot -# - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - - return p -end From b0719465f9cfa07b02c17ab6228840a84ca5aca5 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 25 Mar 2022 14:49:01 +0100 Subject: [PATCH 030/164] for now make GLMakie a required dependency --- Project.toml | 1 + src/HOHQMesh.jl | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Project.toml b/Project.toml index 93128bb2..ac15a5c4 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ authors = ["Michael Schlottke-Lakemper "] version = "0.1.2-pre" [deps] +GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" HOHQMesh_jll = "1d5cbd98-5122-5a8a-bea1-c186d986ee7f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Requires = "ae029012-a4dd-5104-9daa-d747884805df" diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 23d386a3..3f50e84f 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -5,19 +5,19 @@ module HOHQMesh using HOHQMesh_jll: HOHQMesh_jll using Printf -using Requires: @require +#using Requires: @require export generate_mesh export hqmtool_all_features_demo export hqmtool_ice_cream_cone_verbose_demo, hqmtool_ice_cream_cone_demo -function __init__() - # Enable features that depend on the availability of the Makie package - @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin - using .Makie - end -end +# function __init__() +# # Enable features that depend on the availability of the Makie package +# @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin +# using .Makie +# end +# end """ From 9eee28455114c90946dbbe6c977e9a9e5262c77c Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 26 Mar 2022 22:29:31 +0100 Subject: [PATCH 031/164] perform tests on the background grid functions from HQMTool --- test/background_grid_tests.jl | 69 +++++++++++++++++++++++++++++++++++ test/runtests.jl | 3 ++ 2 files changed, 72 insertions(+) create mode 100644 test/background_grid_tests.jl diff --git a/test/background_grid_tests.jl b/test/background_grid_tests.jl new file mode 100644 index 00000000..26488ea5 --- /dev/null +++ b/test/background_grid_tests.jl @@ -0,0 +1,69 @@ +#= + Background Grid Tests exercises routines found in "src/Project/BackgroundGridAPI.jl" functions + +Functions: @ = tested + @ addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + @ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + @ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + @ removeBackgroundGrid!(proj::Project) + @ setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) + @ getBackgroundGridSize(proj::Project) + @ getBackgroundGridLowerLeft(proj::Project) + @ getBackgroundGridSteps(proj::Project) + @ setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) + @ setBackgroundGridSteps!(proj::Project, N::Array{Int}) + @ setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + @ addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) +=# +@testset "Background Grid Tests" begin + + projectName = "TestProject" + projectPath = "./test/TestData" + + p = newProject(projectName, projectPath) +# +# Add with method 1 (when outer boundary is present): [dx,dy,dz] +# + @test hasBackgroundGrid(p) == false + addBackgroundGrid!(p,[0.1,0.2,0.0]) + @test hasBackgroundGrid(p) == true + bgs = getBackgroundGridSize(p) + @test isapprox(bgs,[0.1,0.2,0.0]) + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false +# +# Add with method 2: lower left, dx, nPts +# + addBackgroundGrid!(p,[-1.0,-1.0,0.0],[0.1,0.1,0.0], [10,10,0]) + @test hasBackgroundGrid(p) == true + @test getBackgroundGridSteps(p) == [10,10,0] + @test isapprox(getBackgroundGridSize(p),[0.1,0.1,0.0]) + @test isapprox(getBackgroundGridLowerLeft(p),[-1.0,-1.0,0.0]) +# +# Test undo, redo +# + undo() + @test hasBackgroundGrid(p) == false + redo() + @test hasBackgroundGrid(p) == true + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false +# +# Add with method 3 (No outer bounday, preferred): bounding box + nPts +# + addBackgroundGrid!(p, [10.0,-10.0,-5.0,5.0], [10,10,0]) + @test hasBackgroundGrid(p) == true + @test getBackgroundGridSteps(p) == [10,10,0] + @test isapprox(getBackgroundGridSize(p),[1.5,1.5,0.0]) + @test isapprox(getBackgroundGridLowerLeft(p),[-10.0,-5.0,0.0]) +# +# Editing functions +# + setBackgroundGridSize!(p, 1.0, 1.0) + @test isapprox(getBackgroundGridSize(p), [1.0,1.0,0.0]) + @test getBackgroundGridSteps(p) == [15,15,0] + + removeBackgroundGrid!(p) + @test hasBackgroundGrid(p) == false + +end diff --git a/test/runtests.jl b/test/runtests.jl index c831d54b..19355022 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,5 +42,8 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" +# test background grid routines +include("background_grid_tests.jl") + # Clean up afterwards: delete HOHQMesh output directory @test_nowarn rm(outdir, recursive=true) \ No newline at end of file From 0d0739e4542751032ed27cc2e443cacc144c465b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 12:36:55 +0200 Subject: [PATCH 032/164] export all HQMTool functions, can cleanup later --- src/HOHQMesh.jl | 182 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 177 insertions(+), 5 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 3f50e84f..6e8627a0 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -7,11 +7,6 @@ using HOHQMesh_jll: HOHQMesh_jll using Printf #using Requires: @require -export generate_mesh -export hqmtool_all_features_demo -export hqmtool_ice_cream_cone_verbose_demo, hqmtool_ice_cream_cone_demo - - # function __init__() # # Enable features that depend on the availability of the Makie package # @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin @@ -19,6 +14,183 @@ export hqmtool_ice_cream_cone_verbose_demo, hqmtool_ice_cream_cone_demo # end # end +# Main wrapper to generate a mesh from a control file +export generate_mesh + +# Functions useful to demonstrate the interactive HQMTool +export hqmtool_all_features_demo, + hqmtool_ice_cream_cone_verbose_demo, + hqmtool_ice_cream_cone_demo + +# Generic functions for the HQMTool interface +export new, + add!, + get, + getInnerBoundary, + remove! + +# +# TODO: Go through and cleanup most of this exporting. Most of this will only +# exported for automatic testing purposes +# +# Functions from `BackgroundGridAPI.jl` +export addBackgroundGrid!, + removeBackgroundGrid!, + setBackgroundGridSize!, + getBackgroundGridSize, + getBackgroundGridLowerLeft, + getBackgroundGridSteps, + setBackgroundGridLowerLeft!, + setBackgroundGridSteps! + +# Functions from `ControlInputAPI.jl` +export getControlDict, + getDictInControlDictNamed, + getListInControlDictNamed + +# Functions from `CurvesAPI.jl` +export newParametricEquationCurve, + newEndPointsLineCurve, + newCircularArcCurve, + newSplineCurve, + setCurveName!, + getCurveName, + getCurveType, + setXEqn!, getXEqn, + setYEqn!, getYEqn, + setZEqn!, getZEqn, + setStartPoint!, + getStartPoint, + setEndPoint!, + getEndPoint, + setArcUnits!, + getArcUnits, + setArcCenter!, + getArcCenter, + setArcStartAngle!, + getArcStartAngle, + setArcEndAngle!, + getArcEndAngle, + setArcRadius!, + getArcRadius, + setSplineNKnots!, + getSplineNKnots, + setSplinePoints!, + getSplinePoints, + curvePoint, + curvePoints + +# Functions from `ModelAPI.jl` +export addCurveToOuterBoundary!, + removeOuterBoundaryCurveWithName!, + getOuterBoundaryCurveWithName, + insertOuterBoundaryCurveAtIndex!, + removeOuterBoundaryCurveAtIndex!, + addOuterBoundary!, + removeOuterboundary!, + getOuterBoundaryChainList, + addCurveToInnerBoundary!, + removeInnerBoundaryCurve!, + insertInnerBoundaryCurveAtIndex!, + removeInnerBoundaryCurveAtIndex!, + removeInnerBoundary!, + addInnerBoundaryWithName!, + getChainIndex, + getAllInnerBoundaries, + getInnerBoundaryChainWithName, + getInnerBoundaryCurve, + innerBoundaryIndices, + getModelDict, + getDictInModelDictNamed + +# Functions from `Project.jl` (this is main object of HQMTool) +export openProject, + saveProject, + newProject, + hasBackgroundGrid, + assemblePlotArrays, + projectBounds, + projectGrid, + curveDidChange, + modelDidChange, + backgroundGridDidChange, + refinementWasAdded, + refinementDidChange, + meshWasGenerated, + meshWasDeleted + +# Functions from `RefinementRegionsAPI.jl` +export newRefinementCenter, + addRefinementRegion!, + addRefinementRegionPoints!, + refinementRegionPoints, + getRefinementRegionCenter, + removeRefinementRegion!, + insertRefinementRegion!, + newRefinementLine, + getRefinementRegion, + getAllRefinementRegions, + getRefinementRegion, + setRefinementType!, + getRefinementType, + setRefinementName!, + getRefinementName, + setRefinementLocation!, + getRefinementLocation, + setRefinementGridSize!, + getRefinementGridSize, + setRefinementWidth!, + getRefinementWidth, + setRefinementStart!, + getRefinementStart, + setRefinementEnd!, + getRefinementEnd + +# Functions from `RunParametersAPI.jl` +export addRunParameters!, + removeRunParameters!, + setName!, + getName, + setPolynomialOrder!, + getPolynomialOrder, + setMeshFileFormat!, + getMeshFileFormat, + setPlotFileFormat!, + getPlotFileFormat, + setFileNames!, + getMeshFileName, + getPlotFileName, + getStatsFileName + +# Functions from `SmootherAPI.jl` +export addSpringSmoother!, + setSmoothingStatus!, + getSmoothingStatus, + setSmoothingType!, + getSmoothingType, + setSmoothingIterations!, + getSmoothingIterations, + removeSpringSmoother! + +# Functions from `Undo.jl` +export undo, + redo, + registerUndo, + registerWithUndoManager, + registerRedo, + clearUndoRedo, + undoActionName, + redoActionName, + disableUndo, + enableUndo + +# Functions from `VizProject.jl` +export plotProject!, + updatePlot! + +# Functions from `Meshing.jl` +export generateMesh, removeMesh! + """ generate_mesh(control_file; From f8fdb2fdf63a2fa7fb2e2973ad817c02f901849d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 12:39:28 +0200 Subject: [PATCH 033/164] move all tests into exisitng test folder --- src/Test/BackgroundGridTests.jl | 71 ------------------- src/Test/Tests.jl | 39 ---------- test/background_grid_tests.jl | 2 +- src/Test/CurveTests.jl => test/curve_tests.jl | 32 +++------ src/Test/ModelTests.jl => test/model_tests.jl | 8 +-- .../ProjectTests.jl => test/project_tests.jl | 12 ++-- .../refinement_tests.jl | 20 +++--- .../run_parameters_tests.jl | 27 +++---- test/runtests.jl | 26 ++++++- .../smoother_tests.jl | 6 +- .../test_data}/AllFeatures.control | 0 .../test_data}/TestProject.control | 0 12 files changed, 70 insertions(+), 173 deletions(-) delete mode 100644 src/Test/BackgroundGridTests.jl delete mode 100644 src/Test/Tests.jl rename src/Test/CurveTests.jl => test/curve_tests.jl (89%) rename src/Test/ModelTests.jl => test/model_tests.jl (97%) rename src/Test/ProjectTests.jl => test/project_tests.jl (87%) rename src/Test/RefinementTests.jl => test/refinement_tests.jl (94%) rename src/Test/RunParametersTests.jl => test/run_parameters_tests.jl (77%) rename src/Test/SmootherTests.jl => test/smoother_tests.jl (91%) rename {src/Test/TestData => test/test_data}/AllFeatures.control (100%) rename {src/Test/TestData => test/test_data}/TestProject.control (100%) diff --git a/src/Test/BackgroundGridTests.jl b/src/Test/BackgroundGridTests.jl deleted file mode 100644 index 0ee9e499..00000000 --- a/src/Test/BackgroundGridTests.jl +++ /dev/null @@ -1,71 +0,0 @@ -using Test -include("../HQMTool.jl") -#= - Background Grid Tests tests the "BackgroundGrid.jl" functions - -Functions: @ = tested - @ addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) - @ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - @ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - @ removeBackgroundGrid!(proj::Project) - @ setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) - @ getBackgroundGridSize(proj::Project) - @ getBackgroundGridLowerLeft(proj::Project) - @ getBackgroundGridSteps(proj::Project) - @ setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) - @ setBackgroundGridSteps!(proj::Project, N::Array{Int}) - @ setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) - @ addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) -=# -@testset "Background Grid Tests" begin - - projectName = "TestProject" - projectPath = "./Test/TestData" - - p = newProject(projectName, projectPath) -# -# Add with method 1 (when outer boundary is present): [dx,dy,dz] -# - @test hasBackgroundGrid(p) == false - addBackgroundGrid!(p,[0.1,0.2,0.0]) - @test hasBackgroundGrid(p) == true - bgs = getBackgroundGridSize(p) - @test isapprox(bgs,[0.1,0.2,0.0]) - removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false -# -# Add with method 2: lower left, dx, nPts -# - addBackgroundGrid!(p,[-1.0,-1.0,0.0],[0.1,0.1,0.0], [10,10,0]) - @test hasBackgroundGrid(p) == true - @test getBackgroundGridSteps(p) == [10,10,0] - @test isapprox(getBackgroundGridSize(p),[0.1,0.1,0.0]) - @test isapprox(getBackgroundGridLowerLeft(p),[-1.0,-1.0,0.0]) -# -# Test undo, redo -# - undo() - @test hasBackgroundGrid(p) == false - redo() - @test hasBackgroundGrid(p) == true - removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false -# -# Add with method 3 (No outer bounday, preferred): bounding box + nPts -# - addBackgroundGrid!(p, [10.0,-10.0,-5.0,5.0], [10,10,0]) - @test hasBackgroundGrid(p) == true - @test getBackgroundGridSteps(p) == [10,10,0] - @test isapprox(getBackgroundGridSize(p),[1.5,1.5,0.0]) - @test isapprox(getBackgroundGridLowerLeft(p),[-10.0,-5.0,0.0]) -# -# Editing functions -# - setBackgroundGridSize!(p, 1.0, 1.0) - @test isapprox(getBackgroundGridSize(p), [1.0,1.0,0.0]) - @test getBackgroundGridSteps(p) == [15,15,0] - - removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false - -end diff --git a/src/Test/Tests.jl b/src/Test/Tests.jl deleted file mode 100644 index c681d057..00000000 --- a/src/Test/Tests.jl +++ /dev/null @@ -1,39 +0,0 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - -#= -Set up the test cases for HQMTool -=# -using Test -include("../HQMTool.jl") -include("CurveTests.jl") -include("BackgroundGridTests.jl") -include("ProjectTests.jl") -include("SmootherTests.jl") -include("RunParametersTests.jl") -include("RefinementTests.jl") -include("ModelTests.jl") -include("ProjectTests.jl") diff --git a/test/background_grid_tests.jl b/test/background_grid_tests.jl index 26488ea5..7e1b680f 100644 --- a/test/background_grid_tests.jl +++ b/test/background_grid_tests.jl @@ -18,7 +18,7 @@ Functions: @ = tested @testset "Background Grid Tests" begin projectName = "TestProject" - projectPath = "./test/TestData" + projectPath = "out" p = newProject(projectName, projectPath) # diff --git a/src/Test/CurveTests.jl b/test/curve_tests.jl similarity index 89% rename from src/Test/CurveTests.jl rename to test/curve_tests.jl index 4977e470..e32366ce 100644 --- a/src/Test/CurveTests.jl +++ b/test/curve_tests.jl @@ -1,20 +1,18 @@ -using Test -include("../HQMTool.jl") #= Curve Tests tests the "CurvesAPI.jl" functions Functions: @ = tested - @(as new) newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, + @(as new) newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) - @(as new) newEndPointsLineCurve(name::String, + @(as new) newEndPointsLineCurve(name::String, xStart::Array{Float64}, xEnd::Array{Float64}) - @(as new) newCircularArcCurve(name::String, - center::Array{Float64}, + @(as new) newCircularArcCurve(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String = "degrees") @ newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) @@ -66,14 +64,6 @@ Functions: @ = tested @test getXEqn(crv) == xEqn @test getYEqn(crv) == yEqn @test getZEqn(crv) == zEqn - - # pt = zeros(Float64,2) - # peEquationCurvePoint(xEqn,yEqn,0.5,pt) - # pts = curvePoints(crv,2) - # @test isapprox(pts[1,:],[0.0,0.0]) - # @test isapprox(pts[2,:],[0.5,1.0]) - # @test isapprox(pts[3,:],[1.0,2.0]) - end @testset "EndPointLine Tests" begin @@ -92,7 +82,7 @@ Functions: @ = tested pt = curvePoint(crv, 0.5) @test isapprox(pt,[0.5,0.5,0.0]) - pts = curvePoints(crv,2) + pts = curvePoints(crv, 2) @test isapprox(pts[1,:],[0.0,0.0]) @test isapprox(pts[2,:],[0.5,0.5]) @test isapprox(pts[3,:],[1.0,1.0]) @@ -110,7 +100,6 @@ Functions: @ = tested @test getEndPoint(crv) == xEnd redo() @test getEndPoint(crv) == [2.0,3.0,0.0] - end @testset "CircularArc Tests" begin @@ -151,7 +140,6 @@ Functions: @ = tested @test getArcCenter(crv) == center redo() @test getArcCenter(crv) == [1.0,2.0,0.0] - end @testset "Spline Tests" begin @@ -173,7 +161,7 @@ Functions: @ = tested @test getCurveType(crv) == "SPLINE_CURVE" @test getCurveName(crv) == name @test getSplineNKnots(crv) == nKnots - + pt = curvePoint(crv, 0.5) @test isapprox(pt,[0.5^3,0.5^3 + 0.5^2,0.0]) pt = curvePoint(crv, 0.0) @@ -187,7 +175,7 @@ Functions: @ = tested for j in 1:M+1 tj = (j-1)*d @test isapprox(pts[j,:],[tj^3,tj^3 + tj^2]) - end + end gPts = getSplinePoints(crv) @test isapprox(data,gPts) diff --git a/src/Test/ModelTests.jl b/test/model_tests.jl similarity index 97% rename from src/Test/ModelTests.jl rename to test/model_tests.jl index fafd723c..3684324d 100644 --- a/src/Test/ModelTests.jl +++ b/test/model_tests.jl @@ -1,5 +1,3 @@ -using Test -include("../HQMTool.jl") #= Model Tests tests the "ModelAPI.jl" functions @@ -17,7 +15,7 @@ Functions: @ = tested @@ addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @ removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - @@ insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, + @@ insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int, boundaryName::String) @@ removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) removeInnerBoundary!(proj::Project, chainName::String) @@ -36,7 +34,7 @@ Functions: @ = tested # Project for the model # projectName = "TestProject" - projectPath = "./Test/TestData" + projectPath = "out" p = newProject(projectName, projectPath) # @@ -94,5 +92,5 @@ Functions: @ = tested @test length(ibList) == 3 ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) @test getCurveName(ibc) == "obc2" - + end \ No newline at end of file diff --git a/src/Test/ProjectTests.jl b/test/project_tests.jl similarity index 87% rename from src/Test/ProjectTests.jl rename to test/project_tests.jl index 7abd11bd..726bb9ad 100644 --- a/src/Test/ProjectTests.jl +++ b/test/project_tests.jl @@ -1,5 +1,3 @@ -using Test -include("../HQMTool.jl") #= Project Tests tests the "Project.jl" functions @@ -27,12 +25,12 @@ Functions: @ = tested # Create, save, and read # projectName = "TestProject" - projectPath = "./Test/TestData" + projectPath = "out" p = newProject(projectName, projectPath) saveProject(p) - q = openProject("TestProject.Control",projectPath) + q = openProject("TestProject.control",projectPath) setSmoothingIterations!(q,25) @test getSmoothingIterations(q) == 25 @@ -45,7 +43,9 @@ Functions: @ = tested cDict = getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == false - p = openProject("AllFeatures.control",projectPath) + control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") + p = openProject(control_file, projectPath) + # p = openProject("AllFeatures.control",projectPath) @test hasBackgroundGrid(p) == true bounds = [25.28, -20.0, -5.0, 20.0] @@ -57,7 +57,7 @@ Functions: @ = tested obNames = ["B1", "B2", "B3"] @test p.outerBndryNames == obNames - xGrid = [-23.0, -20.0, -17.0, -14.0, -11.0, -8.0, -5.0, -2.0, 1.0, 4.0, 7.0, + xGrid = [-23.0, -20.0, -17.0, -14.0, -11.0, -8.0, -5.0, -2.0, 1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0, 22.0] yGrid = [-8.0, -5.0, -2.0, 1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0, 22.0, 25.0, 28.0] p.xGrid, p.yGrid = projectGrid(p) diff --git a/src/Test/RefinementTests.jl b/test/refinement_tests.jl similarity index 94% rename from src/Test/RefinementTests.jl rename to test/refinement_tests.jl index 0acc099b..24163fda 100644 --- a/src/Test/RefinementTests.jl +++ b/test/refinement_tests.jl @@ -1,7 +1,5 @@ -using Test -include("../HQMTool.jl") #= - Project Tests tests the "Project.jl" functions + Project Tests tests the "RefinementRegions.jl" functions Functions: @ = tested @ newRefinementCenter @ addRefinementRegion! @@ -29,10 +27,10 @@ Functions: @ = tested @ setRefinementEnd! @ getRefinementEnd =# -@testset "Project Tests" begin +@testset "Refinement Tests" begin projectName = "TestProject" - projectPath = "./Test/TestData" + projectPath = "out" p = newProject(projectName, projectPath) # @@ -58,7 +56,7 @@ Functions: @ = tested redo() @test getRefinementType(cent1) == "sharp" # -# Refinement name +# Refinement name # @test getRefinementName(cent1) == "Center1" setRefinementName!(cent1,"Second") @@ -70,7 +68,7 @@ Functions: @ = tested undo() @test getRefinementName(cent1) == "Center1" # -# Refinement center location +# Refinement center location # @test getRefinementLocation(cent1) == x0 @test getRefinementRegionCenter(cent1) == [1.0,2.0] @@ -81,7 +79,7 @@ Functions: @ = tested redo() @test getRefinementLocation(cent1) == [0.,0.,0.] # -# Refinement width +# Refinement width # @test getRefinementWidth(cent1) == w setRefinementWidth!(cent1,1.0) @@ -91,7 +89,7 @@ Functions: @ = tested redo() @test getRefinementWidth(cent1) == 1.0 # -# Refinement grid size +# Refinement grid size # @test getRefinementGridSize(cent1) == h setRefinementGridSize!(cent1,0.5) @@ -156,6 +154,6 @@ Functions: @ = tested for (i,d) in enumerate(lst) @test getRefinementName(d) == names[i] - end - + end + end diff --git a/src/Test/RunParametersTests.jl b/test/run_parameters_tests.jl similarity index 77% rename from src/Test/RunParametersTests.jl rename to test/run_parameters_tests.jl index ebeb1198..687cb5c7 100644 --- a/src/Test/RunParametersTests.jl +++ b/test/run_parameters_tests.jl @@ -1,12 +1,10 @@ -using Test -include("../HQMTool.jl") #= Run Parameters Tests tests the "RunParameters.jl" functions Functions: @ = tested - @ addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", + @ addRunParameters!(proj::Project, + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) @ removeRunParameters!(proj::Project) @ setName!(proj::Project,name::String) @@ -25,7 +23,7 @@ Functions: @ = tested @testset "Run Parameters Tests" begin projectName = "TestProject" - projectPath = "./Test/TestData" + projectPath = "out" newName = "RPTestsName" p = newProject(projectName, projectPath) # Auto sets up run parameters @@ -39,10 +37,10 @@ Functions: @ = tested redo() @test getName(p) == newName - setFileNames!(p) - @test getMeshFileName(p) == "./Test/TestData/RPTestsName.mesh" - @test getPlotFileName(p) == "./Test/TestData/RPTestsName.tec" - @test getStatsFileName(p) == "./Test/TestData/RPTestsName.txt" + setFileNames!(p, getMeshFileFormat(p)) + @test getMeshFileName(p) == "out/RPTestsName.mesh" + @test getPlotFileName(p) == "out/RPTestsName.tec" + @test getStatsFileName(p) == "out/RPTestsName.txt" @test getPolynomialOrder(p) == 5 setPolynomialOrder!(p,6) @@ -52,6 +50,11 @@ Functions: @ = tested redo() @test getPolynomialOrder(p) == 6 + setMeshFileFormat!(p, "ABAQUS") + @test getMeshFileFormat(p) == "ABAQUS" + undo() + + # ISM-V2 is the default file format type @test getMeshFileFormat(p) == "ISM-V2" setMeshFileFormat!(p,"ISM") @test getMeshFileFormat(p) == "ISM" @@ -64,14 +67,14 @@ Functions: @ = tested @test getMeshFileFormat(p) == "ISM" @test getPlotFileFormat(p) == "skeleton" - setPlotFileFormat!(p,"sem") + setPlotFileFormat!(p,"sem") @test getPlotFileFormat(p) == "sem" undo() @test getPlotFileFormat(p) == "skeleton" redo() @test getPlotFileFormat(p) == "sem" - setPlotFileFormat!(p,"BLORP") + setPlotFileFormat!(p,"BLORP") @test getPlotFileFormat(p) == "sem" removeRunParameters!(p) diff --git a/test/runtests.jl b/test/runtests.jl index 19355022..165c2247 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,8 +42,30 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" -# test background grid routines -include("background_grid_tests.jl") +#@testset "HQMTool features" begin + + # Background grid test routines + include("background_grid_tests.jl") + + # Curve test routines + include("curve_tests.jl") + + # Model test routines + include("model_tests.jl") + + # Project test routines + include("project_tests.jl") + + # Refinement test routines + include("refinement_tests.jl") + + # Run parameters test routines + include("run_parameters_tests.jl") + + # Smoother test routines + include("smoother_tests.jl") + +#end # testset "HQMTool features" # Clean up afterwards: delete HOHQMesh output directory @test_nowarn rm(outdir, recursive=true) \ No newline at end of file diff --git a/src/Test/SmootherTests.jl b/test/smoother_tests.jl similarity index 91% rename from src/Test/SmootherTests.jl rename to test/smoother_tests.jl index f07c9d61..0fe37475 100644 --- a/src/Test/SmootherTests.jl +++ b/test/smoother_tests.jl @@ -1,5 +1,3 @@ -using Test -include("../HQMTool.jl") #= Smoother Tests tests the "SmootherAPI.jl" functions @@ -18,12 +16,12 @@ Functions: @ = tested # Create, save, and read # projectName = "TestProject" - projectPath = "./Test/TestData" + projectPath = "out" p = newProject(projectName, projectPath) saveProject(p) - q = openProject("TestProject.Control",projectPath) + q = openProject("TestProject.control",projectPath) setSmoothingIterations!(q,25) @test getSmoothingIterations(q) == 25 diff --git a/src/Test/TestData/AllFeatures.control b/test/test_data/AllFeatures.control similarity index 100% rename from src/Test/TestData/AllFeatures.control rename to test/test_data/AllFeatures.control diff --git a/src/Test/TestData/TestProject.control b/test/test_data/TestProject.control similarity index 100% rename from src/Test/TestData/TestProject.control rename to test/test_data/TestProject.control From db980c781fd478d8746a9035a65222eadecadccc Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 12:40:39 +0200 Subject: [PATCH 034/164] typo fix in CheatSheet --- docs/src/CheatSheet.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 49ed7d94..b9eec3e3 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -16,7 +16,7 @@ Workflow: plotProject!(p,options) updatePlot!(p,options) - + ## Curves c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* @@ -37,22 +37,22 @@ Workflow: addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* - + ## Accessing items crv = get(p,curveName) *Get a curve in the outer boundary* crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* r = getRefinementRegion(p, name) - + ## Removing from Project removeOuterboundary!(p) *Entire outer boundary curve* - removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve + removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve* remove!(p, name) *Curve in outer boundary* remove!(p, name, innerBoundaryName) *Curve in inner boundary* removeRefinementRegion!(p, name) - + ## Editing items All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. @@ -61,4 +61,4 @@ All items have set/get methods to edit them. Most actions have undo() and redo() generateMesh(p) removeMesh!(p) - + From 22db87769e5199d8405dc7ffe19b53a6e7959e2d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 12:42:51 +0200 Subject: [PATCH 035/164] spacing adjustment and flag possible extra println --- src/Project/RefinementRegionsAPI.jl | 3 ++- src/Project/RunParametersAPI.jl | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 0340c155..33c960ce 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -238,7 +238,8 @@ function getRefinementRegion(proj::Project, name::String) return i,r end end - println("Refinement region with name %s not found",name) + # TODO: Remove? Not sure why this print statement is here + # println("Refinement region with name %s not found",name) return nothing end # diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index a233e863..3f83e7bf 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -26,16 +26,16 @@ """ addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", - polynomialOrder::Int = 5) + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) Add a RUN_PARAMETERS block and set all the parameters in one call. """ function addRunParameters!(proj::Project, - plotFormat::String = "skeleton", - meshFileFormat::String = "ISM-V2", - polynomialOrder::Int = 5) + plotFormat::String = "skeleton", + meshFileFormat::String = "ISM-V2", + polynomialOrder::Int = 5) setFileNames!(proj, meshFileFormat) setPlotFileFormat!(proj, plotFormat) From 0d1d4dbffba0ef747fd8e1b9f92c4e61cedf4fbb Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 13:00:28 +0200 Subject: [PATCH 036/164] generalize file name creation. Tests should pass on Windows now --- test/project_tests.jl | 2 +- test/run_parameters_tests.jl | 7 ++++--- test/smoother_tests.jl | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test/project_tests.jl b/test/project_tests.jl index 726bb9ad..51e0eaf5 100644 --- a/test/project_tests.jl +++ b/test/project_tests.jl @@ -30,7 +30,7 @@ Functions: @ = tested p = newProject(projectName, projectPath) saveProject(p) - q = openProject("TestProject.control",projectPath) + q = openProject("TestProject.control", projectPath) setSmoothingIterations!(q,25) @test getSmoothingIterations(q) == 25 diff --git a/test/run_parameters_tests.jl b/test/run_parameters_tests.jl index 687cb5c7..c08450fa 100644 --- a/test/run_parameters_tests.jl +++ b/test/run_parameters_tests.jl @@ -38,9 +38,10 @@ Functions: @ = tested @test getName(p) == newName setFileNames!(p, getMeshFileFormat(p)) - @test getMeshFileName(p) == "out/RPTestsName.mesh" - @test getPlotFileName(p) == "out/RPTestsName.tec" - @test getStatsFileName(p) == "out/RPTestsName.txt" + # Use string concatenation to make this more general + @test getMeshFileName(p) == joinpath(projectPath, newName*".mesh") + @test getPlotFileName(p) == joinpath(projectPath, newName*".tec") + @test getStatsFileName(p) == joinpath(projectPath, newName*".txt") @test getPolynomialOrder(p) == 5 setPolynomialOrder!(p,6) diff --git a/test/smoother_tests.jl b/test/smoother_tests.jl index 0fe37475..9c56daec 100644 --- a/test/smoother_tests.jl +++ b/test/smoother_tests.jl @@ -21,7 +21,7 @@ Functions: @ = tested p = newProject(projectName, projectPath) saveProject(p) - q = openProject("TestProject.control",projectPath) + q = openProject("TestProject.control", projectPath) setSmoothingIterations!(q,25) @test getSmoothingIterations(q) == 25 From 01c65fd8791404a727120aa75888710834b4a639 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 13:27:36 +0200 Subject: [PATCH 037/164] rename testing files for consistency --- test/runtests.jl | 32 +++++++++---------- ..._grid_tests.jl => test_background_grid.jl} | 0 test/{curve_tests.jl => test_curve.jl} | 0 ...oject_tests.jl => test_hqmtool_project.jl} | 0 test/{model_tests.jl => test_model.jl} | 0 ...refinement_tests.jl => test_refinement.jl} | 0 ...meters_tests.jl => test_run_parameters.jl} | 0 test/{smoother_tests.jl => test_smoother.jl} | 0 8 files changed, 16 insertions(+), 16 deletions(-) rename test/{background_grid_tests.jl => test_background_grid.jl} (100%) rename test/{curve_tests.jl => test_curve.jl} (100%) rename test/{project_tests.jl => test_hqmtool_project.jl} (100%) rename test/{model_tests.jl => test_model.jl} (100%) rename test/{refinement_tests.jl => test_refinement.jl} (100%) rename test/{run_parameters_tests.jl => test_run_parameters.jl} (100%) rename test/{smoother_tests.jl => test_smoother.jl} (100%) diff --git a/test/runtests.jl b/test/runtests.jl index 165c2247..573d8e71 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,30 +42,30 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" -#@testset "HQMTool features" begin +# TODO: add a test for the three demos - # Background grid test routines - include("background_grid_tests.jl") +# Unit tests for the HQMTool functionality - # Curve test routines - include("curve_tests.jl") +# Background grid test routines +include("test_background_grid.jl") - # Model test routines - include("model_tests.jl") +# Curve test routines +include("test_curve.jl") - # Project test routines - include("project_tests.jl") +# Model test routines +include("test_model.jl") - # Refinement test routines - include("refinement_tests.jl") +# HQMTool project test routines +include("test_hqmtool_project.jl") - # Run parameters test routines - include("run_parameters_tests.jl") +# Refinement test routines +include("test_refinement.jl") - # Smoother test routines - include("smoother_tests.jl") +# Run parameters test routines +include("test_run_parameters.jl") -#end # testset "HQMTool features" +# Smoother test routines +include("test_smoother.jl") # Clean up afterwards: delete HOHQMesh output directory @test_nowarn rm(outdir, recursive=true) \ No newline at end of file diff --git a/test/background_grid_tests.jl b/test/test_background_grid.jl similarity index 100% rename from test/background_grid_tests.jl rename to test/test_background_grid.jl diff --git a/test/curve_tests.jl b/test/test_curve.jl similarity index 100% rename from test/curve_tests.jl rename to test/test_curve.jl diff --git a/test/project_tests.jl b/test/test_hqmtool_project.jl similarity index 100% rename from test/project_tests.jl rename to test/test_hqmtool_project.jl diff --git a/test/model_tests.jl b/test/test_model.jl similarity index 100% rename from test/model_tests.jl rename to test/test_model.jl diff --git a/test/refinement_tests.jl b/test/test_refinement.jl similarity index 100% rename from test/refinement_tests.jl rename to test/test_refinement.jl diff --git a/test/run_parameters_tests.jl b/test/test_run_parameters.jl similarity index 100% rename from test/run_parameters_tests.jl rename to test/test_run_parameters.jl diff --git a/test/smoother_tests.jl b/test/test_smoother.jl similarity index 100% rename from test/smoother_tests.jl rename to test/test_smoother.jl From 27d03c89d3c0c131b7777d53a24e2629dfbf8b8b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 14:03:15 +0200 Subject: [PATCH 038/164] properly adjust the Makie reuqirements and exporting --- Project.toml | 1 - src/HOHQMesh.jl | 72 +++++++++++++++++++++---------------------- src/Viz/VizProject.jl | 1 - 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/Project.toml b/Project.toml index ac15a5c4..93128bb2 100644 --- a/Project.toml +++ b/Project.toml @@ -4,7 +4,6 @@ authors = ["Michael Schlottke-Lakemper "] version = "0.1.2-pre" [deps] -GLMakie = "e9467ef8-e4e7-5192-8a1a-b1aee30e663a" HOHQMesh_jll = "1d5cbd98-5122-5a8a-bea1-c186d986ee7f" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Requires = "ae029012-a4dd-5104-9daa-d747884805df" diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 6e8627a0..9b6a0f5e 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -5,14 +5,16 @@ module HOHQMesh using HOHQMesh_jll: HOHQMesh_jll using Printf -#using Requires: @require - -# function __init__() -# # Enable features that depend on the availability of the Makie package -# @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin -# using .Makie -# end -# end +using Requires: @require + +function __init__() + # Enable features that depend on the availability of the Makie package + @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin + include("Viz/VizProject.jl") + using .Makie + export plotProject!, updatePlot! + end +end # Main wrapper to generate a mesh from a control file export generate_mesh @@ -30,7 +32,7 @@ export new, remove! # -# TODO: Go through and cleanup most of this exporting. Most of this will only +# TODO: Go through and cleanup this exporting. Most of this will only be # exported for automatic testing purposes # # Functions from `BackgroundGridAPI.jl` @@ -184,10 +186,6 @@ export undo, disableUndo, enableUndo -# Functions from `VizProject.jl` -export plotProject!, - updatePlot! - # Functions from `Meshing.jl` export generateMesh, removeMesh! @@ -312,22 +310,22 @@ include("ControlFile/ControlFileOperations.jl") include("Curves/CurveOperations.jl") include("Project/Project.jl") include("Project/CurvesAPI.jl") -include("Viz/VizProject.jl") include("Project/Undo.jl") include("Mesh/Meshing.jl") include("Project/Generics.jl") # -#---------------- Routines for testing and demonstrating the HQMTool --------------------------------- +#---------------- Routines for demonstrating the HQMTool --------------------------------- # -function hqmtool_all_features_demo() +function hqmtool_all_features_demo(folder::String) # # Reads in an existing control file, plots the boundary curves and generates # a mesh. # - p = openProject("AllFeatures.control", joinpath(@__DIR__, "..", "examples")) - plotProject!(p,MODEL+REFINEMENTS+GRID) + all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) + p = openProject(all_features_control_file, folder) + plotProject!(p, MODEL+REFINEMENTS+GRID) println("Hit any key to continue and generate the mesh") readline() generateMesh(p) @@ -339,26 +337,26 @@ function hqmtool_ice_cream_cone_verbose_demo(folder::String) # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, # written to `folder`. # - p = newProject("IceCreamCone",folder) + p = newProject("IceCreamCone", folder) # # Outer boundary # - circ = newCircularArcCurve("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - addCurveToOuterBoundary!(p,circ) + circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + addCurveToOuterBoundary!(p, circ) # # Inner boundary # - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p,cone1,"IceCreamCone") - addCurveToInnerBoundary!(p,iceCream,"IceCreamCone") - addCurveToInnerBoundary!(p,cone2,"IceCreamCone") + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p, cone1, "IceCreamCone") + addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") + addCurveToInnerBoundary!(p, cone2, "IceCreamCone") # # Set some control RunParameters to overwrite the defaults # - setPolynomialOrder!(p,4) - setPlotFileFormat!(p,"sem") + setPolynomialOrder!(p, 4) + setPlotFileFormat!(p, "sem") # # To mesh, a background grid is needed # @@ -382,21 +380,21 @@ function hqmtool_ice_cream_cone_demo(folder::String) # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, # written to `path`. # - p = newProject("IceCreamCone",folder) + p = newProject("IceCreamCone", folder) # # Outer boundary # - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") + circ = new("outerCircle", [0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") add!(p,circ) # # Inner boundary # - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") + cone1 = new("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + iceCream = new("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + cone2 = new("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) + add!(p, cone1, "IceCreamCone") + add!(p, iceCream, "IceCreamCone") + add!(p, cone2, "IceCreamCone") # # To mesh, a background grid is needed # diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index d36099ea..adf1df6e 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -23,7 +23,6 @@ --- End License =# -using GLMakie const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 const REFINEMENTS = 8; const ALL = 15 From 9ed90f8d0b182abd8395c6ad58020e5a7cd0f486 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 14:03:39 +0200 Subject: [PATCH 039/164] add CairoMakie to the testing Project.toml --- test/Project.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/Project.toml b/test/Project.toml index bb8371ee..8704c3f9 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,3 +1,7 @@ [deps] +AbaqusReader = "bc6b9049-e460-56d6-94b4-a597b2c0390d" +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -AbaqusReader = "bc6b9049-e460-56d6-94b4-a597b2c0390d" \ No newline at end of file + +[compat] +CairoMakie = "0.6, 0.7" \ No newline at end of file From dc110e9c73cb7248c2661dfe4c0738ae0e0a65b3 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 14:16:03 +0200 Subject: [PATCH 040/164] change generic function from get => getCurve to avoid collision with get function exported by Base --- docs/src/CheatSheet.md | 6 ++-- src/HOHQMesh.jl | 2 +- src/Project/Generics.jl | 64 ++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index b9eec3e3..e480a19d 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -40,9 +40,9 @@ Workflow: ## Accessing items - crv = get(p,curveName) *Get a curve in the outer boundary* - crv = get(p,curveName, boundaryName) *Get a curve in an inner boundary* - indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* + crv = getCurve(p,curveName) *Get a curve in the outer boundary* + crv = getCurve(p,curveName, boundaryName) *Get a curve in an inner boundary* + indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* r = getRefinementRegion(p, name) ## Removing from Project diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 9b6a0f5e..eb923eca 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -27,7 +27,7 @@ export hqmtool_all_features_demo, # Generic functions for the HQMTool interface export new, add!, - get, + getCurve, getInnerBoundary, remove! diff --git a/src/Project/Generics.jl b/src/Project/Generics.jl index c8976072..3aad6af7 100644 --- a/src/Project/Generics.jl +++ b/src/Project/Generics.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -28,16 +28,16 @@ # Creating curves # """ - new(name::String, - xEqn::String, - yEqn::String, + new(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) Create a new parametric equation curve. """ -function new(name::String, - xEqn::String, - yEqn::String, +function new(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) return newParametricEquationCurve(name, xEqn, yEqn, zEqn) end @@ -49,26 +49,26 @@ end Create a new line defined by its end points. """ -function new(name::String, +function new(name::String, xStart::Array{Float64}, xEnd::Array{Float64}) return newEndPointsLineCurve(name, xStart, xEnd) end """ - new(name::String, - center::Array{Float64}, + new(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String) Create a new circular arc. """ -function new(name::String, - center::Array{Float64}, +function new(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String = "degrees") return newCircularArcCurve(name,center,radius,startAngle,endAngle,units) @@ -87,7 +87,7 @@ end new(name::String, nKnots::Int, data::Matrix{Float64}) Create a spline curve from an array of knots -""" +""" function new(name::String, nKnots::Int, data::Matrix{Float64}) return newSplineCurve(name, nKnots, data) end @@ -97,7 +97,7 @@ end """ add!(proj::Project, obj::Dict{String,Any}) -Add a curve to the outer boundary or a refinement reion to +Add a curve to the outer boundary or a refinement reion to the project """ function add!(proj::Project, obj::Dict{String,Any}) @@ -118,20 +118,20 @@ function add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) end """ -get(proj::Project, curveName::String) +getCurve(proj::Project, curveName::String) Get the curve with name `curveName` from the outer boundary. """ -function get(proj::Project, curveName::String) +function getCurve(proj::Project, curveName::String) return getOuterBoundaryCurveWithName(proj, curveName) end """ - get(proj::Project, curveName::String, boundaryName::String) +getCurve(proj::Project, curveName::String, boundaryName::String) Get the curve named `curveName` from the inner boundary named `boundaryName` """ -function get(proj::Project, curveName::String, boundaryName::String) +function getCurve(proj::Project, curveName::String, boundaryName::String) return getInnerBoundaryCurve(proj, curveName, boundaryName) end From 89dfb9c86deb51be2d37630bf51dc2e1556b4748 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 14:17:54 +0200 Subject: [PATCH 041/164] Meshing.jl does not need to use HOHQMesh --- src/Mesh/Meshing.jl | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 15739d62..fd969776 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -3,29 +3,27 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# -using HOHQMesh - function generateMesh(proj::Project) # # Check to be sure background grid has been created (everhtying else is defaults) From a254bfe7a849ba75b8a7a0f47fb679576891be54 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:18:50 +0200 Subject: [PATCH 042/164] make the individual test files module and able to be included independently --- test/test_background_grid.jl | 6 ++++++ test/test_curve.jl | 5 +++++ test/test_hqmtool_project.jl | 6 ++++++ test/test_model.jl | 8 +++++++- test/test_refinement.jl | 6 ++++++ test/test_run_parameters.jl | 6 ++++++ test/test_smoother.jl | 6 ++++++ 7 files changed, 42 insertions(+), 1 deletion(-) diff --git a/test/test_background_grid.jl b/test/test_background_grid.jl index 7e1b680f..79d080d8 100644 --- a/test/test_background_grid.jl +++ b/test/test_background_grid.jl @@ -1,3 +1,4 @@ +module TestBackgroundGrid #= Background Grid Tests exercises routines found in "src/Project/BackgroundGridAPI.jl" functions @@ -15,6 +16,9 @@ Functions: @ = tested @ setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) @ addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) =# +using HOHQMesh +using Test + @testset "Background Grid Tests" begin projectName = "TestProject" @@ -67,3 +71,5 @@ Functions: @ = tested @test hasBackgroundGrid(p) == false end + +end # module \ No newline at end of file diff --git a/test/test_curve.jl b/test/test_curve.jl index e32366ce..d4e63ecd 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -1,3 +1,4 @@ +module TestCurve #= Curve Tests tests the "CurvesAPI.jl" functions @@ -48,6 +49,8 @@ Functions: @ = tested @ setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) @ getSplinePoints(spline::Dict{String,Any}) =# +using HOHQMesh +using Test @testset "Curve Tests" begin @testset "ParametricCurve Tests" begin @@ -188,3 +191,5 @@ Functions: @ = tested # @test isapprox(data,fPts) end + +end # module \ No newline at end of file diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 51e0eaf5..cbd2264a 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -1,3 +1,4 @@ +module TestHQMToolProject #= Project Tests tests the "Project.jl" functions @@ -20,6 +21,9 @@ Functions: @ = tested meshWasDeleted(proj::Project, sender::Project) =# +using HOHQMesh +using Test + @testset "Project Tests" begin # # Create, save, and read @@ -64,3 +68,5 @@ Functions: @ = tested @test isapprox(p.xGrid,xGrid) @test isapprox(p.yGrid,yGrid) end + +end # module \ No newline at end of file diff --git a/test/test_model.jl b/test/test_model.jl index 3684324d..e9926d8a 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -1,3 +1,4 @@ +module TestModel #= Model Tests tests the "ModelAPI.jl" functions @@ -29,6 +30,9 @@ Functions: @ = tested @ getModelDict(proj::Project) @@ getDictInModelDictNamed(proj::Project,name::String) =# +using HOHQMesh +using Test + @testset "Model Tests" begin # # Project for the model @@ -93,4 +97,6 @@ Functions: @ = tested ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) @test getCurveName(ibc) == "obc2" -end \ No newline at end of file +end + +end # module \ No newline at end of file diff --git a/test/test_refinement.jl b/test/test_refinement.jl index 24163fda..ba795ae5 100644 --- a/test/test_refinement.jl +++ b/test/test_refinement.jl @@ -1,3 +1,4 @@ +module TestRefinement #= Project Tests tests the "RefinementRegions.jl" functions Functions: @ = tested @@ -27,6 +28,9 @@ Functions: @ = tested @ setRefinementEnd! @ getRefinementEnd =# +using HOHQMesh +using Test + @testset "Refinement Tests" begin projectName = "TestProject" @@ -157,3 +161,5 @@ Functions: @ = tested end end + +end # module \ No newline at end of file diff --git a/test/test_run_parameters.jl b/test/test_run_parameters.jl index c08450fa..302a39fc 100644 --- a/test/test_run_parameters.jl +++ b/test/test_run_parameters.jl @@ -1,3 +1,4 @@ +module TestRunParameters #= Run Parameters Tests tests the "RunParameters.jl" functions @@ -20,6 +21,9 @@ Functions: @ = tested @ getPlotFileName(proj::Project) @ getStatsFileName(proj::Project) =# +using HOHQMesh +using Test + @testset "Run Parameters Tests" begin projectName = "TestProject" @@ -83,3 +87,5 @@ Functions: @ = tested @test haskey(cDict,"RUN_PARAMETERS") == false end + +end # module \ No newline at end of file diff --git a/test/test_smoother.jl b/test/test_smoother.jl index 9c56daec..981fd850 100644 --- a/test/test_smoother.jl +++ b/test/test_smoother.jl @@ -1,3 +1,4 @@ +module TestSmoother #= Smoother Tests tests the "SmootherAPI.jl" functions @@ -11,6 +12,9 @@ Functions: @ = tested @ getSmoothingIterations(proj::Project) @ removeSpringSmoother!(proj::Project) =# +using HOHQMesh +using Test + @testset "Smoother Tests" begin # # Create, save, and read @@ -42,3 +46,5 @@ Functions: @ = tested @test haskey(cDict,"SPRING_SMOOTHER") == false end + +end # module \ No newline at end of file From 4f5a0a7f8017b8a8afa64e7fed00971f9c40cfe9 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:41:39 +0200 Subject: [PATCH 043/164] add testing for the visualization routines --- test/runtests.jl | 3 ++ test/test_visualization.jl | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 test/test_visualization.jl diff --git a/test/runtests.jl b/test/runtests.jl index 573d8e71..89b3ee87 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -67,5 +67,8 @@ include("test_run_parameters.jl") # Smoother test routines include("test_smoother.jl") +# Visualization test routines +include("test_visualization.jl") + # Clean up afterwards: delete HOHQMesh output directory @test_nowarn rm(outdir, recursive=true) \ No newline at end of file diff --git a/test/test_visualization.jl b/test/test_visualization.jl new file mode 100644 index 00000000..6607d27b --- /dev/null +++ b/test/test_visualization.jl @@ -0,0 +1,66 @@ +module TestVisualization +#= + Visualization tests for "Viz/VizProject.jl" functions + +Functions: @ = tested + + @ plotProject! + @ updatePlot! +=# +using HOHQMesh +using Test + +# We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used +# as a testing backend for HQMTool's Makie-based visualization. +using CairoMakie + +@testset "Visualization Tests" begin + + projectName = "CirclesInCircle" + projectPath = "out" + + p = newProject(projectName, projectPath) + # Outer boundary + circ = new("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") + add!(p, circ) + + # First inner boundary + circ2 = new("inner1", [0.0, 0.0, 0.0], 1.0, 0.0, 360.0, "degrees") + add!(p, circ2, "inner1") + + # To mesh, a background grid is needed + addBackgroundGrid!(p, [0.6, 0.6, 0.0]) + + # Set file format to ISM and corresponding output file names + setMeshFileFormat!(p, "ISM") + meshFileFormat = getMeshFileFormat(p) + setFileNames!(p, meshFileFormat) + + # Show initial the model and grid + @test_nowarn plotProject!(p, HOHQMesh.MODEL + HOHQMesh.GRID) + + # Add another inner boundary + circ3 = new("inner2", [2.0, -1.25, 0.0], 0.5, 0.0, 360.0, "degrees") + add!(p, circ3, "inner2") + + # Set file format to ISM-V2 (to exericise plotting routine) + setMeshFileFormat!(p, "ISM-V2") + meshFileFormat = getMeshFileFormat(p) + setFileNames!(p, meshFileFormat) + + @test_nowarn updatePlot!(p) + + # Add a final inner boundary + circ4 = new("inner3", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") + add!(p, circ4, "inner3") + + # Set file format to ABAQUS (to exericise plotting routine) + setMeshFileFormat!(p, "ABAQUS") + meshFileFormat = getMeshFileFormat(p) + setFileNames!(p, meshFileFormat) + + @test_nowarn updatePlot!(p, HOHQMesh.MODEL + HOHQMesh.GRID) + +end + +end #module \ No newline at end of file From 558d87db2c293727bb703d3321438c80ca3ec117 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:42:55 +0200 Subject: [PATCH 044/164] rearrange Makie includes. shrink resolution --- src/HOHQMesh.jl | 3 ++- src/Viz/VizProject.jl | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index eb923eca..b256f182 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -10,8 +10,9 @@ using Requires: @require function __init__() # Enable features that depend on the availability of the Makie package @require Makie="ee78f7c6-11fb-53f2-987a-cfe4a2b5a57a" begin - include("Viz/VizProject.jl") using .Makie + include("Viz/VizProject.jl") + include("Viz/VizMesh.jl") export plotProject!, updatePlot! end end diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index adf1df6e..98864b35 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -42,7 +42,7 @@ Contents are overlayed in the order: GRID, MESH, MODEL, REFINEMENTS function plotProject!(proj::Project, plotOptions::Int = 0) if isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) + proj.plt = Figure(resolution = (500, 500)) end plt = proj.plt ax = plt[1,1] = Axis(plt) @@ -132,7 +132,7 @@ This version replots the figure with the current options. Legacy. """ function updatePlot!(proj::Project) if !isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) + proj.plt = Figure(resolution = (500, 500)) plotOptions = proj.plotOptions plotProject!(proj, plotOptions) end @@ -148,7 +148,7 @@ Example: updatePlot(p, MESH + MODEL) """ function updatePlot!(proj::Project, plotOptions::Int) if !isnothing(proj.plt) - proj.plt = Figure(resolution = (1500, 1500)) + proj.plt = Figure(resolution = (500, 500)) plotProject!(proj, plotOptions) end end From b5c0c543b7cbc458a5e5ba9af4bdddaf807836f3 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:53:04 +0200 Subject: [PATCH 045/164] adjust function names in Meshing.jl, exporting is easier --- src/Mesh/Meshing.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index fd969776..2c68ea78 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -24,7 +24,7 @@ --- End License =# -function generateMesh(proj::Project) +function generate_mesh(proj::Project) # # Check to be sure background grid has been created (everhtying else is defaults) # @@ -42,7 +42,7 @@ function generateMesh(proj::Project) return nothing end -function removeMesh!(proj::Project) +function remove_mesh!(proj::Project) meshFile = getMeshFileName(proj) rm(meshFile) proj.xMesh = Float64[] From 58e181fd817ccec4db3e5a9057a94a3ce951f3f3 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:53:18 +0200 Subject: [PATCH 046/164] make figure bigger --- src/Viz/VizProject.jl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index 98864b35..61a915a5 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -42,7 +42,7 @@ Contents are overlayed in the order: GRID, MESH, MODEL, REFINEMENTS function plotProject!(proj::Project, plotOptions::Int = 0) if isnothing(proj.plt) - proj.plt = Figure(resolution = (500, 500)) + proj.plt = Figure(resolution = (1000, 1000)) end plt = proj.plt ax = plt[1,1] = Axis(plt) @@ -132,7 +132,7 @@ This version replots the figure with the current options. Legacy. """ function updatePlot!(proj::Project) if !isnothing(proj.plt) - proj.plt = Figure(resolution = (500, 500)) + proj.plt = Figure(resolution = (1000, 1000)) plotOptions = proj.plotOptions plotProject!(proj, plotOptions) end @@ -148,7 +148,7 @@ Example: updatePlot(p, MESH + MODEL) """ function updatePlot!(proj::Project, plotOptions::Int) if !isnothing(proj.plt) - proj.plt = Figure(resolution = (500, 500)) + proj.plt = Figure(resolution = (1000, 1000)) plotProject!(proj, plotOptions) end end From 7b586a9647ea708e7c53f05b0db5815cc8676dfe Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 15:53:43 +0200 Subject: [PATCH 047/164] demos now use generate_mesh --- src/HOHQMesh.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index b256f182..13c2494a 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -187,8 +187,8 @@ export undo, disableUndo, enableUndo -# Functions from `Meshing.jl` -export generateMesh, removeMesh! +# Functions from `Meshing.jl`, generate_mesh is already exported +export remove_mesh! """ @@ -329,7 +329,7 @@ function hqmtool_all_features_demo(folder::String) plotProject!(p, MODEL+REFINEMENTS+GRID) println("Hit any key to continue and generate the mesh") readline() - generateMesh(p) + generate_mesh(p) return p end @@ -371,7 +371,7 @@ function hqmtool_ice_cream_cone_verbose_demo(folder::String) # println("Press any key to continue and generate the mesh") readline() - generateMesh(p) + generate_mesh(p) return p end @@ -415,7 +415,7 @@ function hqmtool_ice_cream_cone_demo(folder::String) # println("Press any key to continue and generate the mesh") readline() - generateMesh(p) + generate_mesh(p) return p end From 8cd90462ca788fb9e9f16926413dd97b910c7a42 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 16:11:20 +0200 Subject: [PATCH 048/164] update visualization tests to cover more code --- src/Mesh/Meshing.jl | 2 +- test/test_visualization.jl | 27 +++++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 2c68ea78..47038b66 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -26,7 +26,7 @@ function generate_mesh(proj::Project) # -# Check to be sure background grid has been created (everhtying else is defaults) +# Check to be sure background grid has been created (everything else is defaults) # controlDict = getControlDict(proj) if !haskey(controlDict,"BACKGROUND_GRID") diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 6607d27b..010955dd 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -1,11 +1,13 @@ module TestVisualization #= - Visualization tests for "Viz/VizProject.jl" functions + Visualization tests for "Viz/VizProject.jl" functions and "Meshing.jl" Functions: @ = tested @ plotProject! @ updatePlot! + @ generate_mesh(p::project) + @ remove_mesh!(p::project) =# using HOHQMesh using Test @@ -39,6 +41,13 @@ using CairoMakie # Show initial the model and grid @test_nowarn plotProject!(p, HOHQMesh.MODEL + HOHQMesh.GRID) + # Create the mesh which contains a plotting update for ISM + @test_nowarn generate_mesh(p) + + # Destroy the mesh and reset the background grid + @test_nowarn remove_mesh!(p) + addBackgroundGrid!(p, [0.6,0.6,0.0]) + # Add another inner boundary circ3 = new("inner2", [2.0, -1.25, 0.0], 0.5, 0.0, 360.0, "degrees") add!(p, circ3, "inner2") @@ -50,16 +59,30 @@ using CairoMakie @test_nowarn updatePlot!(p) + # Create the mesh which contains a plotting update for ISM-V2 + @test_nowarn generate_mesh(p) + + # Destroy the mesh and reset the background grid + @test_nowarn remove_mesh!(p) + addBackgroundGrid!(p, [0.6,0.6,0.0]) + # Add a final inner boundary circ4 = new("inner3", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") add!(p, circ4, "inner3") + # Create a refinement center + cent = newRefinementCenter("Center1", "smooth", [-1.25, -3.0, 0.0], 0.2, 1.0) + addRefinementRegion!(p, cent) + # Set file format to ABAQUS (to exericise plotting routine) setMeshFileFormat!(p, "ABAQUS") meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) - @test_nowarn updatePlot!(p, HOHQMesh.MODEL + HOHQMesh.GRID) + @test_nowarn updatePlot!(p, HOHQMesh.MODEL + HOHQMesh.GRID + HOHQMesh.REFINEMENTS) + + # Create the mesh which contains a plotting update for ABAQUS + @test_nowarn generate_mesh(p) end From 130a029938692e20927cade436b8fff3fa3f11ad Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 19:47:07 +0200 Subject: [PATCH 049/164] add keyword argument to demos such that testing can call them --- src/HOHQMesh.jl | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 13c2494a..a081d4ae 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -21,9 +21,7 @@ end export generate_mesh # Functions useful to demonstrate the interactive HQMTool -export hqmtool_all_features_demo, - hqmtool_ice_cream_cone_verbose_demo, - hqmtool_ice_cream_cone_demo +export run_demo, ice_cream_cone_verbose_demo, ice_cream_cone_demo # Generic functions for the HQMTool interface export new, @@ -319,21 +317,23 @@ include("Project/Generics.jl") #---------------- Routines for demonstrating the HQMTool --------------------------------- # -function hqmtool_all_features_demo(folder::String) +function run_demo(folder::String; called_by_user=true) # # Reads in an existing control file, plots the boundary curves and generates # a mesh. # all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) p = openProject(all_features_control_file, folder) - plotProject!(p, MODEL+REFINEMENTS+GRID) - println("Hit any key to continue and generate the mesh") - readline() + if called_by_user + plotProject!(p, MODEL+REFINEMENTS+GRID) + println("Press enter to continue and generate the mesh") + readline() + end generate_mesh(p) return p end -function hqmtool_ice_cream_cone_verbose_demo(folder::String) +function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, # written to `folder`. @@ -362,21 +362,24 @@ function hqmtool_ice_cream_cone_verbose_demo(folder::String) # To mesh, a background grid is needed # addBackgroundGrid!(p, [0.5,0.5,0.0]) + + if called_by_user # # Show the model and grid # - plotProject!(p, MODEL+GRID) + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + readline() + end # # Generate the mesh and plot # - println("Press any key to continue and generate the mesh") - readline() generate_mesh(p) return p end -function hqmtool_ice_cream_cone_demo(folder::String) +function ice_cream_cone_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, # written to `path`. @@ -406,15 +409,19 @@ function hqmtool_ice_cream_cone_demo(folder::String) setMeshFileFormat!(p, "ABAQUS") meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) + + if called_by_user # # Show the model and grid # - plotProject!(p, MODEL+GRID) + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + readline() + end + # # Generate the mesh and plot # - println("Press any key to continue and generate the mesh") - readline() generate_mesh(p) return p From 25c7c4d18693b9214908c86000441a3f2ceae7c5 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 19:54:03 +0200 Subject: [PATCH 050/164] add testing for the HQMTool demos --- test/runtests.jl | 5 +++-- test/test_hqmtool_demos.jl | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 test/test_hqmtool_demos.jl diff --git a/test/runtests.jl b/test/runtests.jl index 89b3ee87..da70f919 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -42,8 +42,6 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" -# TODO: add a test for the three demos - # Unit tests for the HQMTool functionality # Background grid test routines @@ -55,6 +53,9 @@ include("test_curve.jl") # Model test routines include("test_model.jl") +# HQMTool demonstration test routines +include("test_hqmtool_demos.jl") + # HQMTool project test routines include("test_hqmtool_project.jl") diff --git a/test/test_hqmtool_demos.jl b/test/test_hqmtool_demos.jl new file mode 100644 index 00000000..cce837a1 --- /dev/null +++ b/test/test_hqmtool_demos.jl @@ -0,0 +1,35 @@ +module TestDemos +#= + Tests for the available demos + +Functions: @ = tested + @ hqmtool_all_features_demo(folder::String) + @ hqmtool_ice_cream_cone_verbose_demo(folder::String) + @ hqmtool_ice_cream_cone_demo(folder::String) +=# + +# TODO: Fix this. Not sure how to handle the "Press any key" nonsense. +# Tests wont be very sophisticated, jsut a check that certain files are created +# +# somthing like this @test generate_mesh(control_file, verbose=true) isa String +# or this @test occursin("examples", HOHQMesh.examples_dir()) +using HOHQMesh +using Test + +# We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie is needed +# because the demos call the visualization routines. +using CairoMakie + +@testset "Demo Tests" begin + + projectPath = "out" + + @test_nowarn run_demo( projectPath, called_by_user=false ) + + @test_nowarn ice_cream_cone_verbose_demo( projectPath, called_by_user=false ) + + @test_nowarn ice_cream_cone_demo( projectPath, called_by_user=false ) + +end + +end # module \ No newline at end of file From add93aedf3afa6383c1eb450949b7ac34497925a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 31 Mar 2022 20:22:17 +0200 Subject: [PATCH 051/164] update docs to match changes to the HQMTool structure --- docs/src/CheatSheet.md | 4 +-- docs/src/HQMTool.md | 69 +++++++++++++++++++++++------------------- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index e480a19d..1191b34e 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -59,6 +59,6 @@ All items have set/get methods to edit them. Most actions have undo() and redo() ## Meshing - generateMesh(p) - removeMesh!(p) + generate_mesh(p) + remove_mesh!(p) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 7ba519bb..783a225a 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -24,57 +24,62 @@ HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. ## Introduction -HQMTool is an API to build quad/hex meshes. Two examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. +HQMTool is an API to build quad/hex meshes. Three examples are included to get you started. +The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run - runDemo() + run_demo("out") -The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The script is +where `out` specifies the folder where the resulting mesh and TecPlot files will be saved. - function iceCreamCone(folder::String) +The second example builds a new project consisting of an outer, circular boundary, and an inner +boundary in the shape of an ice cream cone. The "verbose" version of the script is given below. + + function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `path`. This version uses generic versions of - # the API. + # written to `folder`. The keyword arguement `called_by_user` is there for testing purposes. # - p = newProject("IceCreamCone",path) + p = newProject("IceCreamCone", folder) # # Outer boundary # - circ = new("outerCircle",[0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) + circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + addCurveToOuterBoundary!(p, circ) # # Inner boundary # - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) # A line - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") # An arc - cone2 = new("cone2", [-1.0,0.0,0.0],[0.0,-3.0,0.0]) # A line - add!(p,cone1,"IceCreamCone") - add!(p,iceCream,"IceCreamCone") - add!(p,cone2,"IceCreamCone") + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p, cone1, "IceCreamCone") + addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") + addCurveToInnerBoundary!(p, cone2, "IceCreamCone") # # Set some control RunParameters to overwrite the defaults # - setPolynomialOrder!(p,4) - setPlotFileFormat!(p,"sem") + setPolynomialOrder!(p, 4) + setPlotFileFormat!(p, "sem") # # To mesh, a background grid is needed # - addBackgroundGrid!(p, [0.1,0.1,0.0]) + addBackgroundGrid!(p, [0.5,0.5,0.0]) + + if called_by_user # # Show the model and grid # - plotProject!(p, MODEL+GRID) + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + readline() + end # # Generate the mesh and plot # - println("Press any key to continue and generate the mesh") - readline() - generateMesh(p) - updatePlot!(p, MODEL+MESH) + generate_mesh(p) return p - end + end The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. @@ -85,7 +90,7 @@ To develop the model, one adds curves to the outer boundary or to multiple inner - Lines defined by their end points - Circular arcs -In the example, the outer boundary is a closed circular arc with center at [0,0,0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. +In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. @@ -109,7 +114,10 @@ To save a control file for HOHQMesh, simply invoke where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. -Methods are available to edit a model. For example to move the center of the outer boundary +The third example `ice_cream_cone_demo` is identical to that which was explained above except that the function calls +use the generic version of, e.g., `new` or `add!`. + +Methods are available to edit a model. For example to move the center of the outer boundary. ## Basic Moves @@ -175,7 +183,6 @@ The supplied name will be the default name of the mesh and plot files generated (Return:Project) proj = openProject(fileName::String, folder::String) - #### Saving a project saveProject(proj::Project) @@ -347,9 +354,9 @@ Example: To edit curves they can be accessed by name: [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - Generic: get(...) + Generic: getCurve(...) [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) - Generic: get(...) + Generic: getCurve(...) - Deleting boundary curves @@ -401,7 +408,7 @@ The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should Example: - cone1 = new("cone1", [0.0,-3.0,0.0],[1.0,0.0,0.0]) + cone1 = new("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) ##### Circular Arc [Return:Dict{String,Any}] newCircularArcCurve(name::String, @@ -416,7 +423,7 @@ Example: Example: - iceCream = new("iceCream",[0.0,0.0,0.0],1.0,0.0,180.0,"degrees") + iceCream = new("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") ##### Spline Curve From ab88d02d5fab7dafcd0966f1f7c7fc2bc147d89b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 07:32:34 +0200 Subject: [PATCH 052/164] add a 3D smoke test for a simple extrusion --- examples/HalfCircle3DRot.control | 49 ++++++++++++++++++++++++++++++++ test/runtests.jl | 11 ++++++- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 examples/HalfCircle3DRot.control diff --git a/examples/HalfCircle3DRot.control b/examples/HalfCircle3DRot.control new file mode 100644 index 00000000..5036ed5b --- /dev/null +++ b/examples/HalfCircle3DRot.control @@ -0,0 +1,49 @@ +\begin{CONTROL_INPUT} + + \begin{RUN_PARAMETERS} + mesh file name = examples/HalfCircle3DR.inp + plot file name = examples/HalfCircle3DR.tec + stats file name = none + mesh file format = ABAQUS + polynomial order = 5 + plot file format = sem + \end{RUN_PARAMETERS} + + \begin{BACKGROUND_GRID} + background grid size = [0.75,0.75,0.75] + \end{BACKGROUND_GRID} + + \begin{SIMPLE_ROTATION} + direction = 1 + rotation angle factor = 1.0 + subdivisions = 6 + start surface name = start + end surface name = end + \end{SIMPLE_ROTATION} + + \begin{SPRING_SMOOTHER} + smoothing = ON + smoothing type = LinearAndCrossBarSpring + number of iterations = 15 + \end{SPRING_SMOOTHER} + +\end{CONTROL_INPUT} + +\begin{MODEL} + + \begin{OUTER_BOUNDARY} + \begin{PARAMETRIC_EQUATION_CURVE} + name = circle + xEqn = x(t) = 4.0*cos(pi*t) + yEqn = y(t) = 0.5 + 4.0*sin(pi*t) + zEqn = z(t) = 0.0 + \end{PARAMETRIC_EQUATION_CURVE} + \begin{END_POINTS_LINE} + name = cut + xStart = [-4.0,0.5,0.0] + xEnd = [4.0,0.5,0.0] + \end{END_POINTS_LINE} + \end{OUTER_BOUNDARY} + +\end{MODEL} +\end{FILE} diff --git a/test/runtests.jl b/test/runtests.jl index da70f919..5936f4e8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -22,7 +22,7 @@ isdir(outdir) && rm(outdir, recursive=true) @test generate_mesh(control_file, verbose=true) isa String end - @testset "generate_mesh() with ABAQUS output" begin + @testset "generate_mesh() in 2D with ABAQUS output" begin control_file = joinpath(HOHQMesh.examples_dir(), "IceCreamCone_Abaqus.control") generate_mesh(control_file) parse_mesh = abaqus_read_mesh(joinpath(outdir, "IceCreamCone_Abaqus.inp")) @@ -31,6 +31,15 @@ isdir(outdir) && rm(outdir, recursive=true) @test parse_mesh["elements"][114] == reference_ids end + @testset "generate_mesh() in 3D with ABAQUS output" begin + control_file = joinpath(HOHQMesh.examples_dir(), "HalfCircle3DRot.control") + generate_mesh(control_file) + parse_mesh = abaqus_read_mesh(joinpath(outdir, "HalfCircle3DRot.inp")) + # set some reference values for comparison. These are the corner IDs for element 246 + reference_ids = [297, 321, 322, 302, 363, 387, 388, 368] + @test parse_mesh["elements"][246] == reference_ids + end + @testset "generate_mesh() with invalid format" begin # Create temporary control file option that is invalid mktemp() do path, io From 0719c9c0560dd4b343fc93549239c1f87a3d4e25 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 09:07:55 +0200 Subject: [PATCH 053/164] remove TODO --- src/Project/RefinementRegionsAPI.jl | 79 ++++++++++++++--------------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 33c960ce..4cb2cdb2 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -3,36 +3,36 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# """ -newRefinementCenter(type, +newRefinementCenter(type, center, meshSize, width ) Create refinement center of `type` "smooth" or "sharp" centered at `center = [x,y,z]`` with a mesh size `meshSize` spread over a radius `width`. """ -function newRefinementCenter(name::String, type::String, +function newRefinementCenter(name::String, type::String, x0::Array{Float64}, h::Float64, w::Float64 ) disableUndo() @@ -130,7 +130,7 @@ function getRefinementRegionCenter(r::Dict{String,Any}) xEnd = realArrayForKeyFromDictionary("x1",r) xAvg = 0.5*(xStart + xEnd) return xAvg[1:2] - end + end end """ removeRefinementRegion!(proj::Project, name::String) @@ -144,7 +144,7 @@ function removeRefinementRegion!(proj::Project, name::String) deleteat!(proj.refinementRegionLoc,i) deleteat!(proj.refinementRegionNames,i) deleteat!(proj.refinementRegionPoints,i) - registerWithUndoManager(proj,insertRefinementRegion!, (r,i,), "Remove Refinement Region") + registerWithUndoManager(proj,insertRefinementRegion!, (r,i,), "Remove Refinement Region") enableNotifications() postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) end @@ -155,7 +155,7 @@ Used by undo() """ function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) lst = getAllRefinementRegions(proj) - registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Set Insert Refinement Region") + registerWithUndoManager(proj,removeRefinementRegion!, (r["name"],), "Set Insert Refinement Region") insert!(lst,indx,r) x = refinementRegionPoints(r) insert!(proj.refinementRegionPoints,indx,x) @@ -168,7 +168,7 @@ end # -------------------------------------------------------------------------------------- # """ - newRefinementLine(type, + newRefinementLine(type, start, end, meshSize, width ) @@ -176,7 +176,7 @@ end Create refinement line of type "smooth" or "sharp" between `start` = [x,y,z] and `end` = [x,y,z] with a mesh size `meshSize` spread over a width `width`. """ -function newRefinementLine(name::String, type::String, +function newRefinementLine(name::String, type::String, x0::Array{Float64}, x1::Array{Float64}, h::Float64, w::Float64 ) @@ -236,10 +236,9 @@ function getRefinementRegion(proj::Project, name::String) for (i,r) in enumerate(lst) if r["name"] == name return i,r - end - end - # TODO: Remove? Not sure why this print statement is here - # println("Refinement region with name %s not found",name) + end + end + println("Refinement region with name %s not found",name) return nothing end # @@ -258,7 +257,7 @@ function setRefinementType!(r::Dict{String,Any}, type::String) if haskey(r,"type") oldType = r["type"] - registerWithUndoManager(r,setRefinementType!, (oldType,), "Set Refinement Type") + registerWithUndoManager(r,setRefinementType!, (oldType,), "Set Refinement Type") end r["type"] = type end @@ -268,7 +267,7 @@ end """ getRefinementType(r::Dict{String,Any}) -Return the type of refinement, either "smooth" or "sharp". `r` is the dictionary that +Return the type of refinement, either "smooth" or "sharp". `r` is the dictionary that represents the refinement region. """ function getRefinementType(r::Dict{String,Any}) @@ -277,13 +276,13 @@ end """ setRefinementName!(r::Dict{String,Any}, type) -Set a name for the refinement region.`r` is the dictionary that +Set a name for the refinement region.`r` is the dictionary that represents the refinement region. """ function setRefinementName!(r::Dict{String,Any}, name::String) if haskey(r,"name") oldName = r["name"] - registerWithUndoManager(r,setRefinementName!, (oldName,), "Set Refinement Name") + registerWithUndoManager(r,setRefinementName!, (oldName,), "Set Refinement Name") end r["name"] = name postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) @@ -294,7 +293,7 @@ end """ getRefinementName(r::Dict{String,Any}) -Return name of the refinement. `r` is the dictionary that +Return name of the refinement. `r` is the dictionary that represents the refinement region. """ function getRefinementName(r::Dict{String,Any}) @@ -316,7 +315,7 @@ end function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x0") old = r["x0"] - registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") + registerWithUndoManager(r,setRefinementLocation!, (old,), "Set Refinement Center") end r["x0"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) @@ -328,7 +327,7 @@ end """ getRefinementLocation(r::Dict{String,Any}) -Return Array{Float64} of the location of the refinement center.`r` is the dictionary that +Return Array{Float64} of the location of the refinement center.`r` is the dictionary that represents the refinement region. """ function getRefinementLocation(r::Dict{String,Any}) @@ -340,13 +339,13 @@ end """ setRefinementGridSize!(r::Dict{String,Any}, h) -Set the grid size, `h` for the refinement region. `r` is the dictionary that +Set the grid size, `h` for the refinement region. `r` is the dictionary that represents the refinement region. """ function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) if haskey(r,"h") old = r["h"] - registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") + registerWithUndoManager(r,setRefinementGridSize!, (old,), "Set Refinement Grid Size") end r["h"] = string(h) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) @@ -362,7 +361,7 @@ end """ getRefinementGridSize(r::Dict{String,Any}) -Returns the grid size,h, as Float64. `r` is the dictionary that +Returns the grid size,h, as Float64. `r` is the dictionary that represents the refinement region. """ function getRefinementGridSize(r::Dict{String,Any}) @@ -374,13 +373,13 @@ end """ setRefinementWidth!(r::Dict{String,Any}, width) -Set the width of the refinement region. `r` is the dictionary that +Set the width of the refinement region. `r` is the dictionary that represents the refinement region. """ function setRefinementWidth!(r::Dict{String,Any},w::Float64) if haskey(r,"w") old = r["w"] - registerWithUndoManager(r,setRefinementWidth!, (old,), "Set Refinement Width") + registerWithUndoManager(r,setRefinementWidth!, (old,), "Set Refinement Width") end r["w"] = string(w) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) @@ -396,7 +395,7 @@ end """ getRefinementWidth(r::Dict{String,Any}) -Returns the region width,w, as Float64. `r` is the dictionary that +Returns the region width,w, as Float64. `r` is the dictionary that represents the refinement region. """ function getRefinementWidth(r::Dict{String,Any}) @@ -418,7 +417,7 @@ end function setRefinementStart!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x0") old = r["x0"] - registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") + registerWithUndoManager(r,setRefinementStart!, (old,), "Set Refinement Start") end r["x0"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) @@ -429,7 +428,7 @@ end """ getRefinementStart (r::Dict{String,Any}) -Return Array{Float64} of the start location of the refinement line. `r` is the dictionary that +Return Array{Float64} of the start location of the refinement line. `r` is the dictionary that represents the refinement region. """ function getRefinementStart(r::Dict{String,Any}) @@ -451,7 +450,7 @@ end function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x1") old = r["x1"] - registerWithUndoManager(r,setRefinementEnd!, (old,), "Set Refinement End") + registerWithUndoManager(r,setRefinementEnd!, (old,), "Set Refinement End") end r["x1"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) From 3fe01809bcb85067721a1adaee343cf26689b08a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 09:09:14 +0200 Subject: [PATCH 054/164] remove unnecessary test data files --- test/test_data/AllFeatures.control | 112 ----------------------------- test/test_data/TestProject.control | 15 ---- 2 files changed, 127 deletions(-) delete mode 100644 test/test_data/AllFeatures.control delete mode 100644 test/test_data/TestProject.control diff --git a/test/test_data/AllFeatures.control b/test/test_data/AllFeatures.control deleted file mode 100644 index 8244db77..00000000 --- a/test/test_data/AllFeatures.control +++ /dev/null @@ -1,112 +0,0 @@ -\begin{MODEL} - \begin{OUTER_BOUNDARY} - \begin{END_POINTS_LINE} - name = B1 - xEnd = [20.0,-5,0.0] - xStart = [-20.0,-5.0,0.0] - \end{END_POINTS_LINE} - \begin{END_POINTS_LINE} - name = B2 - xEnd = [0.0,25.28,0.0] - xStart = [20.0,-5.0,0.0] - \end{END_POINTS_LINE} - \begin{END_POINTS_LINE} - name = B3 - xEnd = [-20.0,-5.0,0.0] - xStart = [0.0,25.28,0.0] - \end{END_POINTS_LINE} - \end{OUTER_BOUNDARY} - \begin{INNER_BOUNDARIES} - \begin{CHAIN} - name = Arc - \begin{CIRCULAR_ARC} - units = degrees - name = InnerCircle1 - radius = 1.0 - start angle = 0.0 - center = [-12.0,-1.5,0.0] - end angle = 360.0 - \end{CIRCULAR_ARC} - \end{CHAIN} - \begin{CHAIN} - name = InnerSpline - \begin{SPLINE_CURVE} - name = Spline - nKnots = 26 - \begin{SPLINE_DATA} - 0.0 -3.5 3.5 0.0 - 0.03846153846153846 -3.2 5.0 0.0 - 0.07692307692307693 -2.0 6.0 0.0 - 0.115384615384615 1.0 6.0 0.0 - 0.153846153846154 2.0 5.0 0.0 - 0.192307692307692 3.0 4.0 0.0 - 0.230769230769231 5.0 4.0 0.0 - 0.269230769230769 6.0 5.0 0.0 - 0.307692307692308 7.0 7.0 0.0 - 0.346153846153846 8.0 8.0 0.0 - 0.384615384615385 9.0 8.0 0.0 - 0.423076923076923 10.0 7.0 0.0 - 0.461538461538462 11.0 5.0 0.0 - 0.5 11.0 3.0 0.0 - 0.538461538461539 10.0 2.0 0.0 - 0.576923076923077 9.0 1.0 0.0 - 0.615384615384615 7.0 1.0 0.0 - 0.653846153846154 5.0 1.0 0.0 - 0.692307692307692 3.0 1.0 0.0 - 0.730769230769231 1.0 0.0 0.0 - 0.769230769230769 0.0 -1.0 0.0 - 0.807692307692308 -1.0 -1.0 0.0 - 0.846153846153846 -2.0 -0.8 0.0 - 0.884615384615385 -2.5 0.0 0.0 - 0.923076923076923 -3.0 1.0 0.0 - 1.0 -3.5 3.5 0.0 - \end{SPLINE_DATA} - \end{SPLINE_CURVE} - \end{CHAIN} - \begin{CHAIN} - name = InnerCircle2 - \begin{PARAMETRIC_EQUATION_CURVE} - name = Circle1 - yEqn = f(t) = 17.0 + 1.5*sin(2*pi*t) - zEqn = z(t) = 0.0 - xEqn = f(t) = 1.5*cos(2*pi*t) - \end{PARAMETRIC_EQUATION_CURVE} - \end{CHAIN} - \end{INNER_BOUNDARIES} -\end{MODEL} -\begin{CONTROL_INPUT} - \begin{REFINEMENT_REGIONS} - \begin{REFINEMENT_CENTER} - name = center - w = 0.5 - x0 = [9.0,-3.0,0.0] - type = smooth - h = 0.1 - \end{REFINEMENT_CENTER} - \begin{REFINEMENT_LINE} - name = line - x1 = [2.0,14.0,0.0] - w = 0.5 - x0 = [-6.0,9.0,0.0] - type = smooth - h = 0.2 - \end{REFINEMENT_LINE} - \end{REFINEMENT_REGIONS} - \begin{SPRING_SMOOTHER} - smoothing type = LinearAndCrossbarSpring - smoothing = ON - number of iterations = 25 - \end{SPRING_SMOOTHER} - \begin{BACKGROUND_GRID} - background grid size = [3.0,3.0,0.0] - \end{BACKGROUND_GRID} - \begin{RUN_PARAMETERS} - mesh file name = examples/AllFeatures.mesh - plot file format = skeleton - plot file name = examples/AllFeatures.tec - stats file name = none - mesh file format = ISM-V2 - polynomial order = 4 - \end{RUN_PARAMETERS} -\end{CONTROL_INPUT} -\end{FILE} diff --git a/test/test_data/TestProject.control b/test/test_data/TestProject.control deleted file mode 100644 index d897d338..00000000 --- a/test/test_data/TestProject.control +++ /dev/null @@ -1,15 +0,0 @@ -\begin{CONTROL_INPUT} - \begin{SPRING_SMOOTHER} - smoothing type = LinearAndCrossbarSpring - smoothing = ON - \end{SPRING_SMOOTHER} - \begin{RUN_PARAMETERS} - mesh file name = ./Test/TestData/TestProject.mesh - plot file format = skeleton - plot file name = ./Test/TestData/TestProject.tec - stats file name = ./Test/TestData/TestProject.txt - mesh file format = ISM-V2 - polynomial order = 5 - \end{RUN_PARAMETERS} -\end{CONTROL_INPUT} -\end{FILE} From 601eec0d71eb03b3d9dbdd6b6211bfc3dea58cb6 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 09:09:45 +0200 Subject: [PATCH 055/164] add to tests that trigger some of the error statement printing --- test/test_hqmtool_project.jl | 5 ++++- test/test_smoother.jl | 16 ++++++++++++++-- test/test_visualization.jl | 4 ++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index cbd2264a..96d83806 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -49,7 +49,6 @@ using Test control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p = openProject(control_file, projectPath) - # p = openProject("AllFeatures.control",projectPath) @test hasBackgroundGrid(p) == true bounds = [25.28, -20.0, -5.0, 20.0] @@ -67,6 +66,10 @@ using Test p.xGrid, p.yGrid = projectGrid(p) @test isapprox(p.xGrid,xGrid) @test isapprox(p.yGrid,yGrid) + + # Exercise some dictionary printing routines for the AllFeatures project + HOHQMesh.showDescription(p.projectDictionary) + HOHQMesh.stringForKeyFromDictionary("CONTROL_INPUT", p.projectDictionary) end end # module \ No newline at end of file diff --git a/test/test_smoother.jl b/test/test_smoother.jl index 981fd850..007a9b0a 100644 --- a/test/test_smoother.jl +++ b/test/test_smoother.jl @@ -25,8 +25,13 @@ using Test p = newProject(projectName, projectPath) saveProject(p) - q = openProject("TestProject.control", projectPath) - setSmoothingIterations!(q,25) + q = openProject( projectName*".control", projectPath ) + + # Trigger error statements by setting incorrect values in the smoother options + addSpringSmoother!(p, "PAUSE", "LinearSpring", 50) + addSpringSmoother!(p, "ON" , "MagicSprings", 50) + + setSmoothingIterations!(q, 25) @test getSmoothingIterations(q) == 25 @test getSmoothingStatus(q) == "ON" @@ -34,11 +39,18 @@ using Test setSmoothingStatus!(q,"OFF") @test getSmoothingStatus(q) == "OFF" + + # Trigger error statement by setting an invalid spring status setSmoothingStatus!(q,"UNKNOWN") @test getSmoothingStatus(q) == "OFF" + setSmoothingType!(q,"LinearSpring") @test getSmoothingType(q) == "LinearSpring" + # Trigger error statement by setting an invalid spring type + setSmoothingType!(q,"TorsionalSpring") + @test getSmoothingType(q) == "LinearSpring" + cDict = getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == true removeSpringSmoother!(q) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 010955dd..814b4721 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -70,9 +70,9 @@ using CairoMakie circ4 = new("inner3", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") add!(p, circ4, "inner3") - # Create a refinement center + # Create a refinement center and add it with the generic method cent = newRefinementCenter("Center1", "smooth", [-1.25, -3.0, 0.0], 0.2, 1.0) - addRefinementRegion!(p, cent) + add!(p, cent) # Set file format to ABAQUS (to exericise plotting routine) setMeshFileFormat!(p, "ABAQUS") From f0833d75887a043e76ddd9691227ad330c3259fd Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 10:47:13 +0200 Subject: [PATCH 056/164] add testing for spline read in from a file --- test/test_curve.jl | 26 ++++++----- test/test_spline_curve_data.txt | 78 +++++++++++++++++++++++++++++++++ test/test_visualization.jl | 6 +-- 3 files changed, 95 insertions(+), 15 deletions(-) create mode 100644 test/test_spline_curve_data.txt diff --git a/test/test_curve.jl b/test/test_curve.jl index d4e63ecd..7de1c996 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -166,29 +166,31 @@ using Test @test getSplineNKnots(crv) == nKnots pt = curvePoint(crv, 0.5) - @test isapprox(pt,[0.5^3,0.5^3 + 0.5^2,0.0]) + @test isapprox(pt, [0.5^3, 0.5^3 + 0.5^2, 0.0]) pt = curvePoint(crv, 0.0) - @test isapprox(pt,[0.0,0.0,0.0]) + @test isapprox(pt, [0.0, 0.0, 0.0]) # # The curvePoints for the spline has M = max(N,nKnots*2) values # - M = max(nPts,nKnots*2) - pts = curvePoints(crv,M) - d = 1.0/M + M = max(nPts, nKnots*2) + pts = curvePoints(crv, M) + d = 1.0 / M for j in 1:M+1 - tj = (j-1)*d - @test isapprox(pts[j,:],[tj^3,tj^3 + tj^2]) + tj = (j-1) * d + @test isapprox(pts[j, :], [tj^3, tj^3 + tj^2]) end gPts = getSplinePoints(crv) - @test isapprox(data,gPts) - end + @test isapprox(data, gPts) # # Get spline data from a file # - # fSpline = newSplineCurve("fromFile", "TestData/SplineData.txt") - # fPts = getSplinePoints(fSpline) - # @test isapprox(data,fPts) + fSpline = newSplineCurve("fromFile", joinpath(@__DIR__, "test_spline_curve_data.txt")) + fPts = getSplinePoints(fSpline) + # Use point value 11 from the file as the test point + control_pt = [0.131578947368421, -0.657970237227418, 0.051342865473934, 0.0] + @test isapprox(control_pt, fPts[11, :]) + end end diff --git a/test/test_spline_curve_data.txt b/test/test_spline_curve_data.txt new file mode 100644 index 00000000..2e576e1d --- /dev/null +++ b/test/test_spline_curve_data.txt @@ -0,0 +1,78 @@ +77 +0.000000000000000 -1.000000000000000 -1.000000000000000 0.000000000000000 +0.013157894736842 -0.995929487847041 -0.984513308895507 0.000000000000000 +0.026315789473684 -0.984006935621602 -0.940263574448587 0.000000000000000 +0.039473684210526 -0.964665819673838 -0.870566304959074 0.000000000000000 +0.052631578947368 -0.938339616353904 -0.778737008726803 0.000000000000000 +0.065789473684211 -0.905461802011955 -0.668091194051611 0.000000000000000 +0.078947368421053 -0.866465852998146 -0.541944369233333 0.000000000000000 +0.092105263157895 -0.821785245662633 -0.403612042571803 0.000000000000000 +0.105263157894737 -0.771853456355570 -0.256409722366859 0.000000000000000 +0.118421052631579 -0.717103961427114 -0.103652916918335 0.000000000000000 +0.131578947368421 -0.657970237227418 0.051342865473934 0.000000000000000 +0.144736842105263 -0.594885760106638 0.205262116510112 0.000000000000000 +0.157894736842105 -0.528284006414929 0.354789327890363 0.000000000000000 +0.171052631578947 -0.458598452502447 0.496608991314852 0.000000000000000 +0.184210526315789 -0.386262574719347 0.627405598483744 0.000000000000000 +0.197368421052632 -0.311709849415783 0.743863641097203 0.000000000000000 +0.210526315789474 -0.235373752941912 0.842667610855393 0.000000000000000 +0.223684210526316 -0.157687761647887 0.920501999458480 0.000000000000000 +0.236842105263158 -0.079085351883865 0.974051298606627 0.000000000000000 +0.250000000000000 0.000000000000000 1.000000000000000 0.000000000000000 +0.263157894736842 0.079132214191990 0.996076583425322 0.000000000000000 +0.276315789473684 0.157864797034136 0.964185481015558 0.000000000000000 +0.289473684210526 0.235748651406911 0.907275112990232 0.000000000000000 +0.302631578947368 0.312334680190782 0.828293899568867 0.000000000000000 +0.315789473684211 0.387173786266220 0.730190260970987 0.000000000000000 +0.328947368421053 0.459816872513694 0.615912617416116 0.000000000000000 +0.342105263157895 0.529814841813676 0.488409389123779 0.000000000000000 +0.355263157894737 0.596718597046633 0.350628996313498 0.000000000000000 +0.368421052631579 0.660079041093037 0.205519859204799 0.000000000000000 +0.381578947368421 0.719447076833358 0.056030398017204 0.000000000000000 +0.394736842105263 0.774373607148064 -0.094890967029763 0.000000000000000 +0.407894736842105 0.824409534917626 -0.244295815716577 0.000000000000000 +0.421052631578947 0.869105763022515 -0.389235727823714 0.000000000000000 +0.434210526315789 0.908013194343199 -0.526762283131652 0.000000000000000 +0.447368421052632 0.940682731760148 -0.653927061420865 0.000000000000000 +0.460526315789474 0.966665278153833 -0.767781642471830 0.000000000000000 +0.473684210526316 0.985511736404724 -0.865377606065024 0.000000000000000 +0.486842105263158 0.996773009393289 -0.943766531980922 0.000000000000000 +0.500000000000000 1.000000000000000 -1.000000000000000 0.000000000000000 +0.513157894736842 0.994898517068294 -1.032013465103201 0.000000000000000 +0.526315789473684 0.981793993293483 -1.041277883073334 0.000000000000000 +0.539473684210526 0.961166767333847 -1.030148084893675 0.000000000000000 +0.552631578947368 0.933497177847667 -1.000978901547498 0.000000000000000 +0.565789473684211 0.899265563493221 -0.956125164018079 0.000000000000000 +0.578947368421053 0.858952262928790 -0.897941703288692 0.000000000000000 +0.592105263157895 0.813037614812655 -0.828783350342616 0.000000000000000 +0.605263157894737 0.762001957803095 -0.751004936163122 0.000000000000000 +0.618421052631579 0.706325630558390 -0.666961291733489 0.000000000000000 +0.631578947368421 0.646488971736821 -0.579007248036990 0.000000000000000 +0.644736842105263 0.582972319996667 -0.489497636056901 0.000000000000000 +0.657894736842105 0.516256013996209 -0.400787286776498 0.000000000000000 +0.671052631578947 0.446820392393727 -0.315231031179056 0.000000000000000 +0.684210526315789 0.375145793847500 -0.235183700247849 0.000000000000000 +0.697368421052632 0.301712557015808 -0.163000124966155 0.000000000000000 +0.710526315789474 0.227001020556933 -0.101035136317247 0.000000000000000 +0.723684210526316 0.151491523129152 -0.051643565284402 0.000000000000000 +0.736842105263158 0.075664403390749 -0.017180242850895 0.000000000000000 +0.750000000000000 0.000000000000000 0.000000000000000 0.000000000000000 +0.763157894736842 -0.075055193385125 -0.001715681169683 0.000000000000000 +0.776315789473684 -0.149190063107908 -0.020972184616666 0.000000000000000 +0.789473684210526 -0.222127340511945 -0.055672422052361 0.000000000000000 +0.802631578947368 -0.293589756940828 -0.103719305188178 0.000000000000000 +0.815789473684211 -0.363300043738154 -0.163015745735530 0.000000000000000 +0.828947368421053 -0.430980932247516 -0.231464655405828 0.000000000000000 +0.842105263157895 -0.496355153812509 -0.306968945910482 0.000000000000000 +0.855263157894737 -0.559145439776727 -0.387431528960906 0.000000000000000 +0.868421052631579 -0.619074521483765 -0.470755316268511 0.000000000000000 +0.881578947368421 -0.675865130277217 -0.554843219544706 0.000000000000000 +0.894736842105263 -0.729239997500677 -0.637598150500906 0.000000000000000 +0.907894736842105 -0.778921854497740 -0.716923020848520 0.000000000000000 +0.921052631578947 -0.824633432612001 -0.790720742298961 0.000000000000000 +0.934210526315789 -0.866097463187054 -0.856894226563639 0.000000000000000 +0.947368421052632 -0.903036677566493 -0.913346385353967 0.000000000000000 +0.960526315789474 -0.935173807093912 -0.957980130381355 0.000000000000000 +0.973684210526316 -0.962231583112907 -0.988698373357216 0.000000000000000 +0.986842105263158 -0.983932736967071 -1.003404025992960 0.000000000000000 +1.000000000000000 -1.000000000000000 -1.000000000000000 0.000000000000000 diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 814b4721..fd4548c1 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -26,9 +26,9 @@ using CairoMakie circ = new("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") add!(p, circ) - # First inner boundary - circ2 = new("inner1", [0.0, 0.0, 0.0], 1.0, 0.0, 360.0, "degrees") - add!(p, circ2, "inner1") + # First inner boundary via a spline from a file + spline1 = new("inner1", joinpath(@__DIR__, "test_spline_curve_data.txt")) + add!(p, spline1, "inner1") # To mesh, a background grid is needed addBackgroundGrid!(p, [0.6, 0.6, 0.0]) From 7775864b497079007abc2eb0432d1bed73bdb8e5 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 10:51:29 +0200 Subject: [PATCH 057/164] add attempt to generate mesh without background grid to trigger error in testing --- test/test_visualization.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index fd4548c1..d250fb22 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -30,6 +30,9 @@ using CairoMakie spline1 = new("inner1", joinpath(@__DIR__, "test_spline_curve_data.txt")) add!(p, spline1, "inner1") + # Attempt to generate the mesh before the background grid is set. Throws an error. + @test_nowarn generate_mesh(p) + # To mesh, a background grid is needed addBackgroundGrid!(p, [0.6, 0.6, 0.0]) From 97732bb207e03eadcfe10ad878e1dc782673f5e8 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 12:05:42 +0200 Subject: [PATCH 058/164] add tests using the getCurve and getInnerBoundary functions --- test/test_visualization.jl | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index d250fb22..7729c7ff 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -26,10 +26,18 @@ using CairoMakie circ = new("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") add!(p, circ) + # Test getting the outer curve name + dict = getCurve(p, "outerCircle") + @test dict["TYPE"] == "CIRCULAR_ARC" + # First inner boundary via a spline from a file - spline1 = new("inner1", joinpath(@__DIR__, "test_spline_curve_data.txt")) + spline1 = new("big_spline", joinpath(@__DIR__, "test_spline_curve_data.txt")) add!(p, spline1, "inner1") + # Test extracting an inner boundary chain with the generic function + tup = getInnerBoundary(p, "inner1") + @test tup[2]["TYPE"] == "CHAIN" + # Attempt to generate the mesh before the background grid is set. Throws an error. @test_nowarn generate_mesh(p) @@ -51,9 +59,18 @@ using CairoMakie @test_nowarn remove_mesh!(p) addBackgroundGrid!(p, [0.6,0.6,0.0]) - # Add another inner boundary - circ3 = new("inner2", [2.0, -1.25, 0.0], 0.5, 0.0, 360.0, "degrees") - add!(p, circ3, "inner2") + # Add another inner boundary via a spline with given data points + data = [ [0.0 1.75 -1.0 0.0] + [0.25 2.1 -0.5 0.0] + [0.5 2.7 -1.0 0.0] + [0.75 0.6 -2.0 0.0] + [1.0 1.75 -1.0 0.0] ] + spline2 = newSplineCurve("small_spline", 5, data) + add!(p, spline2, "inner2") + + # Test getting the inner curve and test + dict = getCurve(p, "small_spline", "inner2") + @test dict["TYPE"] == "SPLINE_CURVE" # Set file format to ISM-V2 (to exericise plotting routine) setMeshFileFormat!(p, "ISM-V2") @@ -70,7 +87,7 @@ using CairoMakie addBackgroundGrid!(p, [0.6,0.6,0.0]) # Add a final inner boundary - circ4 = new("inner3", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") + circ4 = new("innerCircle", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") add!(p, circ4, "inner3") # Create a refinement center and add it with the generic method From f37439ab03391cc1e60a170d32e0adaddbb4faee Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 14:32:34 +0200 Subject: [PATCH 059/164] added a test for the generic spline creation --- test/test_visualization.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 7729c7ff..658ee9b7 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -65,7 +65,7 @@ using CairoMakie [0.5 2.7 -1.0 0.0] [0.75 0.6 -2.0 0.0] [1.0 1.75 -1.0 0.0] ] - spline2 = newSplineCurve("small_spline", 5, data) + spline2 = new("small_spline", 5, data) add!(p, spline2, "inner2") # Test getting the inner curve and test @@ -104,6 +104,9 @@ using CairoMakie # Create the mesh which contains a plotting update for ABAQUS @test_nowarn generate_mesh(p) + # Destroy everything + remove_mesh!(p) + end end #module \ No newline at end of file From 0141839515871c49c77def09845fea5171f87009 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 20:13:27 +0200 Subject: [PATCH 060/164] add comment and blank line to control file --- examples/AllFeatures.control | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/examples/AllFeatures.control b/examples/AllFeatures.control index 8244db77..dd44f8a8 100644 --- a/examples/AllFeatures.control +++ b/examples/AllFeatures.control @@ -1,3 +1,7 @@ +% +% Control file that exercises available 2D features +% + \begin{MODEL} \begin{OUTER_BOUNDARY} \begin{END_POINTS_LINE} From 6382105026901cc943042b286415d697800faa4e Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 20:36:28 +0200 Subject: [PATCH 061/164] export parametric equation evaluators --- src/HOHQMesh.jl | 4 +++- test/test_visualization.jl | 3 --- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index a081d4ae..5ac890d4 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -79,7 +79,9 @@ export newParametricEquationCurve, setSplinePoints!, getSplinePoints, curvePoint, - curvePoints + curvePoints, + peEquationCurvePoints, + peEquationCurvePoint # Functions from `ModelAPI.jl` export addCurveToOuterBoundary!, diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 658ee9b7..ad615e1a 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -104,9 +104,6 @@ using CairoMakie # Create the mesh which contains a plotting update for ABAQUS @test_nowarn generate_mesh(p) - # Destroy everything - remove_mesh!(p) - end end #module \ No newline at end of file From 629aa2da1cba60acad0206874fd1c72cf7305961 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 20:51:19 +0200 Subject: [PATCH 062/164] move plotProject outside if statement. Should cover more routines --- src/HOHQMesh.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 5ac890d4..13270b6c 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -326,8 +326,9 @@ function run_demo(folder::String; called_by_user=true) # all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) p = openProject(all_features_control_file, folder) + + plotProject!(p, MODEL+REFINEMENTS+GRID) if called_by_user - plotProject!(p, MODEL+REFINEMENTS+GRID) println("Press enter to continue and generate the mesh") readline() end @@ -365,11 +366,11 @@ function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # addBackgroundGrid!(p, [0.5,0.5,0.0]) + plotProject!(p, MODEL+GRID) if called_by_user # # Show the model and grid # - plotProject!(p, MODEL+GRID) println("Press enter to continue and generate the mesh") readline() end @@ -412,11 +413,11 @@ function ice_cream_cone_demo(folder::String; called_by_user=true) meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) + plotProject!(p, MODEL+GRID) if called_by_user # # Show the model and grid # - plotProject!(p, MODEL+GRID) println("Press enter to continue and generate the mesh") readline() end From bd8c989963c835b31ec93d7c62d9f81de6161e9f Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 21:26:58 +0200 Subject: [PATCH 063/164] exercise parametric eqn eval at a single point and the redoActionName --- src/Curves/CurveOperations.jl | 73 ++++++++++++++++++----------------- test/test_curve.jl | 3 ++ test/test_model.jl | 1 + 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index 6fc8f060..cbc261c7 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -33,7 +33,7 @@ function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, if units == "degrees" fctr = pi/180.0 end - + theta::Float64 = 0.0 for i = 1:length(t) theta = thetaStart + (thetaEnd - thetaStart)*t[i] @@ -42,7 +42,7 @@ function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, end end -function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, +function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Float64, point::Array{Float64}) fctr::Float64 = 1.0 if units == "degrees" @@ -74,7 +74,7 @@ function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Floa yArgM = match(argRegex,argPart) yArg = Symbol(yArgM.match) ey = Meta.parse(eqString) - + for i = 1:length(t) points[i,1] = evalWithDict(ex,Dict(xArg=> t[i])) points[i,2] = evalWithDict(ey,Dict(yArg=> t[i])) @@ -82,7 +82,7 @@ function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Floa end function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) - + argPart,eqString = keyAndValueFromString(xEqn) xArgM = match(argRegex,argPart) xArg = Symbol(xArgM.match) @@ -92,10 +92,10 @@ function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) yArgM = match(argRegex,argPart) yArg = Symbol(yArgM.match) ey = Meta.parse(eqString) - - point[1] = evalWithDict(ex,Dict(xArg=> t)) - point[2] = evalWithDict(ey,Dict(yArg=> t)) - + + point[1] = evalWithDict(ex, Dict(xArg=> t)) + point[2] = evalWithDict(ey, Dict(yArg=> t)) + end function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Array{Float64,2}) @@ -110,7 +110,7 @@ function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Ar t = (i-1)/(nPts-1) points[i,1] = evalSpline(xSpline,t) points[i,2] = evalSpline(ySpline,t) - end + end end function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::Array{Float64}) @@ -122,13 +122,14 @@ function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::A point[2] = evalSpline(ySpline,t) end -function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) - ex = Meta.parse(s) - assignments = [:($sym = $val) for (sym,val) in locals] - eval(:(let $(assignments...); $ex; end)) -end +# This function evaluates a string as an equation, might be redundant code +# function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) +# ex = Meta.parse(s) +# assignments = [:($sym = $val) for (sym,val) in locals] +# eval(:(let $(assignments...); $ex; end)) +# end -function evalWithDict(ex::Expr, locals::Dict{Symbol}) +function evalWithDict(ex, locals::Dict{Symbol}) assignments = [:($sym = $val) for (sym,val) in locals] eval(:(let $(assignments...); $ex; end)) end @@ -145,7 +146,7 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) t = zeros(Float64,N+1) for i = 1:N+1 t[i] = (i-1)/N - end + end peEquationCurvePoints(xEqn,yEqn,t,x) elseif curveType == "END_POINTS_LINE" xStart = realArrayForKeyFromDictionary("xStart",crvDict) @@ -154,7 +155,7 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) t = zeros(Float64,3) for i = 1:3 t[i] = (i-1)/2.0 - end + end endPointsLineCurvePoints(xStart,xEnd,t,x) elseif curveType == "CIRCULAR_ARC" @@ -168,7 +169,7 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) t = zeros(Float64,N+1) for i = 1:N+1 t[i] = (i-1)/N - end + end arcCurvePoints(center,radius,startAngle,endAngle,units,t,x) elseif curveType == "SPLINE_CURVE" @@ -180,12 +181,12 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) t = zeros(Float64,M+1) for i = 1:M+1 t[i] = (i-1)/M - end + end splineCurvePoints(nKnots,splineData,x) else - end + end return x end @@ -195,7 +196,7 @@ function chainPoints(chain::Array{Dict{String,Any}}, N::Int) for crvDict in chain push!(x,curvePoints(crvDict,N)) - end + end return x end @@ -207,7 +208,7 @@ function curvePoint(crvDict::Dict{String,Any}, t::Float64) xEqn = crvDict["xEqn"] yEqn = crvDict["yEqn"] x = zeros(Float64,3) - peEquationCurvePoint(xEqn,yEqn,t,x) + peEquationCurvePoint(xEqn, yEqn, t, x) elseif curveType == "END_POINTS_LINE" xStart = realArrayForKeyFromDictionary("xStart",crvDict) xEnd = realArrayForKeyFromDictionary("xEnd",crvDict) @@ -228,7 +229,7 @@ function curvePoint(crvDict::Dict{String,Any}, t::Float64) splineCurvePoint(nKnots,splineData,t,x) else - end + end return x end diff --git a/test/test_curve.jl b/test/test_curve.jl index 7de1c996..5873bc66 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -67,6 +67,9 @@ using Test @test getXEqn(crv) == xEqn @test getYEqn(crv) == yEqn @test getZEqn(crv) == zEqn + + value = curvePoint(crv, 0.25) + @test value == [0.25, 0.5, 0.0] end @testset "EndPointLine Tests" begin diff --git a/test/test_model.jl b/test/test_model.jl index e9926d8a..1074632f 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -58,6 +58,7 @@ using Test @test undoActionName() == "Add Curve" undo() @test length(obList) == 2 + @test redoActionName() == "Add Curve" redo() @test length(obList) == 3 From 36aea70cc84036ac48b3be503643e231fa1ca79b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 1 Apr 2022 22:17:16 +0200 Subject: [PATCH 064/164] exercise more curve arc and spline routines --- src/Misc/NotificationCenter.jl | 76 +++++++++++++++++----------------- test/test_curve.jl | 36 ++++++++++++++++ 2 files changed, 75 insertions(+), 37 deletions(-) diff --git a/src/Misc/NotificationCenter.jl b/src/Misc/NotificationCenter.jl index b2ae9586..97f9ca34 100644 --- a/src/Misc/NotificationCenter.jl +++ b/src/Misc/NotificationCenter.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -40,7 +40,7 @@ HQMNotificationsON = true """ addObserver(observer::Any, note::String, fnction::Any) -fnction is the function to be executed (called) when a +fnction is the function to be executed (called) when a notification of name `note` is given. The function called upon notification must have the signature @@ -54,28 +54,30 @@ function addObserver(observer::Any, note::String, fnction::Any) end push!(HQMNotificationCenter[note],noteObj) end -""" - unRegisterForNotification(observer::Any, note::String) -Remove the observer from being notified by the notification `note` -""" -function unRegisterForNotification(observer::Any, note::String) - if haskey(HQMNotificationCenter,note) - global observers = HQMNotificationCenter[note] - - for i = 1:length(observers) - global noteObj = observers[i] - noteObserver = noteObj.observer - if noteObserver === observer - deleteat!(observers,i) - break - end - end - if isempty(observers) - delete!(HQMNotificationCenter,note) - end - end -end +# This is unused. We never remove notifications +# """ +# unRegisterForNotification(observer::Any, note::String) + +# Remove the observer from being notified by the notification `note` +# """ +# function unRegisterForNotification(observer::Any, note::String) +# if haskey(HQMNotificationCenter,note) +# global observers = HQMNotificationCenter[note] + +# for i = 1:length(observers) +# global noteObj = observers[i] +# noteObserver = noteObj.observer +# if noteObserver === observer +# deleteat!(observers,i) +# break +# end +# end +# if isempty(observers) +# delete!(HQMNotificationCenter,note) +# end +# end +# end """ postNotificationWithName(sender::Any, name::String, userInfo::Tuple) @@ -84,7 +86,7 @@ Executes the function associated with the observer for the notification `note` function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) if haskey(HQMNotificationCenter,note) && HQMNotificationsON global observers = HQMNotificationCenter[note] - + for i = 1:length(observers) global noteObj = observers[i] f = noteObj.fcn @@ -93,7 +95,7 @@ function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) f(observer,sender) else f(observer,sender,userInfo...) - end + end end end end diff --git a/test/test_curve.jl b/test/test_curve.jl index 5873bc66..1c48e947 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -70,6 +70,16 @@ using Test value = curvePoint(crv, 0.25) @test value == [0.25, 0.5, 0.0] + + # tests to reset curve name and equation definitions + setCurveName!(crv, "WhatACurve") + setXEqn!(crv, "t^2") + setYEqn!(crv, "1.5*t") + setZEqn!(crv, "t^3") + @test getCurveName(crv) == "WhatACurve" + @test getXEqn(crv) == "t^2" + @test getYEqn(crv) == "1.5*t" + @test getZEqn(crv) == "t^3" end @testset "EndPointLine Tests" begin @@ -133,6 +143,9 @@ using Test @test isapprox(pts[2,:],[0.0,2.0]) @test isapprox(pts[3,:],[-2.0,0.0]) + # purposly trigger warning with invalid units + setArcUnits!(crv,"Rankine") + setArcUnits!(crv,"radians") @test getArcUnits(crv) == "radians" undo() @@ -146,6 +159,13 @@ using Test @test getArcCenter(crv) == center redo() @test getArcCenter(crv) == [1.0,2.0,0.0] + + setArcStartAngle!(crv, 90.0) + @test getArcStartAngle(crv) == 90.0 + setArcEndAngle!(crv, 270.0) + @test getArcEndAngle(crv) == 270.0 + setArcRadius!(crv, 1.5) + @test getArcRadius(crv) == 1.5 end @testset "Spline Tests" begin @@ -186,6 +206,22 @@ using Test gPts = getSplinePoints(crv) @test isapprox(data, gPts) # +# Create a new set of points to replace the existing ones +# + data = zeros(Float64, 10, 4) + for j in 1:10 + tj = 0.1*(j-1) + xj = tj^4 + yj = tj^2 + 0.5*tj + zj = 0.0 + data[j,:] = [tj,xj,yj,zj] + end + setSplineNKnots!(crv, 10) + setSplinePoints!(crv, data) + # test the new points + gPts = getSplinePoints(crv) + @test isapprox(data, gPts) +# # Get spline data from a file # fSpline = newSplineCurve("fromFile", joinpath(@__DIR__, "test_spline_curve_data.txt")) From 657eff753cd22d08f388abc827fbbf68b950e518 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Fri, 1 Apr 2022 14:55:17 -0700 Subject: [PATCH 065/164] Fix two bugs 1. Strip trailing blanks for control file line so that the reader will consider lines with only blanks to be empty and skipped. 2. Add refinement region names to refinement regions in the NASCA0012.control file. --- examples/NACA0012.control | 2 ++ src/ControlFile/ControlFileOperations.jl | 1 + 2 files changed, 3 insertions(+) diff --git a/examples/NACA0012.control b/examples/NACA0012.control index a8155a9d..cea3a477 100644 --- a/examples/NACA0012.control +++ b/examples/NACA0012.control @@ -24,6 +24,7 @@ \begin{REFINEMENT_REGIONS} \begin{REFINEMENT_CENTER} + name = TECenter type = smooth x0 = [1.0,0.0,0.0] h = 0.10 @@ -31,6 +32,7 @@ \end{REFINEMENT_CENTER} \begin{REFINEMENT_CENTER} + name = LECenter type = smooth x0 = [0.0,0.0,0.0] h = 0.05 diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index 2e38c2be..f4cfa25e 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -117,6 +117,7 @@ end function performImport(collection, f::IOStream) for line in eachline(f) + line = rstrip(line) # # ---------------- # Start of a block From 60082fa9dbe37cf3c703ad3ff043a488fd45a441 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 2 Apr 2022 19:41:39 +0200 Subject: [PATCH 066/164] added NACA0012 read in and some tests --- test/test_hqmtool_project.jl | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 96d83806..9a3b4b53 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -47,6 +47,7 @@ using Test cDict = getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == false + # read in the AllFeatures example control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p = openProject(control_file, projectPath) @@ -70,6 +71,18 @@ using Test # Exercise some dictionary printing routines for the AllFeatures project HOHQMesh.showDescription(p.projectDictionary) HOHQMesh.stringForKeyFromDictionary("CONTROL_INPUT", p.projectDictionary) + + # Use the NACA0012 example because it sets the background grid differently + control_file = joinpath(HOHQMesh.examples_dir(), "NACA0012.control") + p = openProject(control_file, projectPath) + + sizes = [2.0, 2.0, 1.0] + @test isapprox( getBackgroundGridSize(p) , sizes ) + steps = [20, 20 ,20] + @test isapprox( getBackgroundGridSteps(p), steps ) + lower_left = [-20.0 , -20.0 , 0.0] + @test isapprox( getBackgroundGridLowerLeft(p) , lower_left ) + end end # module \ No newline at end of file From 09d6ad164b59da4928011d898afae27f5f584eb7 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 2 Apr 2022 20:53:30 +0200 Subject: [PATCH 067/164] add tests that purposly has curves that do not join --- test/test_hqmtool_project.jl | 8 ++++++++ test/test_model.jl | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 9a3b4b53..03118cc7 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -82,6 +82,14 @@ using Test @test isapprox( getBackgroundGridSteps(p), steps ) lower_left = [-20.0 , -20.0 , 0.0] @test isapprox( getBackgroundGridLowerLeft(p) , lower_left ) + # Update the background grid starting point + new_lower_left = [-25.0, -10.0, 0.0] + setBackgroundGridLowerLeft!(p, new_lower_left) + @test isapprox( getBackgroundGridLowerLeft(p) , new_lower_left ) + # # Update the size of the background grid + # setBackgroundGridSize!(p, 2.5, 1.5, 1.0) + # new_sizes = [2.5, 1.5, 1.0] + # @test isapprox( getBackgroundGridSize(p) , new_sizes ) end diff --git a/test/test_model.jl b/test/test_model.jl index 1074632f..4aabbd18 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -98,6 +98,24 @@ using Test ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) @test getCurveName(ibc) == "obc2" +# +# Purposely create outer / inner boundary curves that do +# not join in a new project. This will trigger error statements. +# + obc1 = new("obc1",[0.0,0.0,0.0], [2.0,0.0,0.0]) + obc2 = new("obc2",[3.0,0.0,0.0], [1.0,1.0,0.0]) + + # Failing outer boundary + add!(p, obc1) + add!(p, obc2) + + # Failing inner boundary + line = newEndPointsLineCurve("line", [0.0,-2.0,0.0], [1.0,0.0,0.0]) + halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + + addCurveToInnerBoundary!(p, line, "failCurve") + addCurveToInnerBoundary!(p, halfCircle , "failCurve") + end end # module \ No newline at end of file From 749bfd531d7106e80d0ccdaa88d791fa1142dc0a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 2 Apr 2022 21:18:38 +0200 Subject: [PATCH 068/164] add generic remove of the outer boundary --- test/test_visualization.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index ad615e1a..8453a5a3 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -104,6 +104,9 @@ using CairoMakie # Create the mesh which contains a plotting update for ABAQUS @test_nowarn generate_mesh(p) + # Remove the outer boundary from the project + @test remove!(p, "outerCircle") + end end #module \ No newline at end of file From fefa9e3486bc2ee6f0630ee6e0abd2a0bfb66f3b Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Sat, 2 Apr 2022 13:58:59 -0700 Subject: [PATCH 069/164] Update ModelAPI.jl Delete innerBoundaryNames entry when all component curves are gone. --- src/Project/ModelAPI.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 1d7203b2..cdac1a0d 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -253,6 +253,7 @@ function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::S deleteat!(ibChains,i) deleteat!(proj.innerBoundaryChainNames,i) deleteat!(proj.innerBoundaryPoints,i) + deleteat!(proj.innerBoundaryNames,i) end proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) From 7d623af7a00cdb796a9266868270b556c1119408 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 09:52:09 +0200 Subject: [PATCH 070/164] fix bug in VizMesh and actually make the model test fail --- src/Viz/VizMesh.jl | 10 ++++++---- test/test_model.jl | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index d4f3aee3..9e990698 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -103,10 +103,12 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS if sum(temp) == 0 # straight-sided edge so just skip the boundary labels readline(f) - else - # curved edge so skip the boundary polynomial and the labels - for i = 1:nBndy+1 - readline(f) + else # sum(temp) > 0 + # At least one curved edge, so skip any boundary polynomial(s) and the labels + for j = 1:sum(temp) + for i = 1:nBndy+1 + readline(f) + end end readline(f) end diff --git a/test/test_model.jl b/test/test_model.jl index 4aabbd18..67478664 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -111,9 +111,9 @@ using Test # Failing inner boundary line = newEndPointsLineCurve("line", [0.0,-2.0,0.0], [1.0,0.0,0.0]) - halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.5, 0.0, 180.0, "degrees") - addCurveToInnerBoundary!(p, line, "failCurve") + add!(p, line, "failCurve") addCurveToInnerBoundary!(p, halfCircle , "failCurve") end From 152d46f5120cf2853374cffcbfdc5988fe5c5332 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 10:45:29 +0200 Subject: [PATCH 071/164] fix bug in removeInnerBoundary. Add output if a requested curveName boundaryName configuration does not exist --- src/Project/ModelAPI.jl | 51 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index cdac1a0d..591ab593 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -83,7 +83,7 @@ function getOuterBoundaryCurveWithName(proj::Project, name::String) if crv["name"] == name return crv end - end + end end """ insertOuterBoundaryCurveAtIndex(proj::Project, crv::Dict{String,Any}, indx::Int) @@ -153,7 +153,7 @@ Get the array of outer boundary curves. """ function getOuterBoundaryChainList(proj::Project) outerBndryDict = getDictInModelDictNamed(proj,"OUTER_BOUNDARY") - if haskey(outerBndryDict,"LIST") + if haskey(outerBndryDict,"LIST") lst = outerBndryDict["LIST"] return lst else @@ -219,20 +219,20 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin lst = chain["LIST"] if isempty(lst) println("No curve ", name, " in boundary ", chainName) #TODO Replace with error() - return + return end indx = getChainIndex(lst,name) removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) end -function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, +function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int, boundaryName::String) i, chain = getInnerBoundaryChainWithName(proj,boundaryName) lst = chain["LIST"] insert!(lst,indx,crv) innerBoundaryPoints = proj.innerBoundaryPoints[i] insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) - insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + insert!(proj.innerBoundaryNames[i],indx,crv["name"]) proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end @@ -265,9 +265,9 @@ end Remove an entire inner boundary """ function removeInnerBoundary!(proj::Project, chainName::String) - i,crv = getInnerBoundaryChainWithName(p,chainName) - deleteat!(proj.innerBoundaryChainNames,i) - deleteat!(proj.innerBoundaryPoints,i) + i, crv = getInnerBoundaryChainWithName(proj, chainName) + deleteat!(proj.innerBoundaryChainNames, i) + deleteat!(proj.innerBoundaryPoints, i) ibChains = getAllInnerBoundaries(proj) deleteat!(ibChains,i) end @@ -309,7 +309,7 @@ function getChainIndex(chain::Vector{Dict{String, Any}},name) return i end end - return 0 + return 0 end """ getAllInnerBoundaries(proj::Project) @@ -321,7 +321,7 @@ Returns an array of the inner boundaries # function getAllInnerBoundaries(proj::Project) innerBndryDict = getDictInModelDictNamed(proj,"INNER_BOUNDARIES") - if haskey(innerBndryDict,"LIST") + if haskey(innerBndryDict,"LIST") lst = innerBndryDict["LIST"] return lst else @@ -329,7 +329,7 @@ function getAllInnerBoundaries(proj::Project) innerBndryDict["LIST"] = lst return lst end - return nothing + return nothing end # # -------------------------------------------------------------------------------------- @@ -366,13 +366,14 @@ end """ function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + i, chain = getInnerBoundaryChainWithName(proj, boundaryName) lst = chain["LIST"] for crv in lst if crv["name"] == curveName return crv end end + println("No curve ", curveName, " in boundary ", boundaryName, ". Try again.") return nothing end """ From cacec953cd9360f42a2a187aa3c2128ad2f4ea74 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 11:22:36 +0200 Subject: [PATCH 072/164] bug fix in the chain index count of getInnerBoundaryChainWithName --- src/Project/ModelAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 591ab593..9de93520 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -346,13 +346,13 @@ function getInnerBoundaryChainWithName(proj::Project, name::String) # See if there is an inner boundary with that name # l = length(lst) - i = 1 + i = 0 if l > 0 for chain in lst bCurveName = chain["name"] + i = i + 1 if bCurveName == name return i, chain - i = i + 1 end end end From 817e2ff02d6ce2c83ff4221be235ae2c9e11452e Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 11:22:55 +0200 Subject: [PATCH 073/164] add calls to the generic remove for inner boundaries --- test/test_visualization.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 8453a5a3..0311d6c9 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -105,7 +105,12 @@ using CairoMakie @test_nowarn generate_mesh(p) # Remove the outer boundary from the project - @test remove!(p, "outerCircle") + remove!(p, "outerCircle") + + # Remove the inner boundaries from the project + remove!(p, "small_spline", "inner2") + remove!(p, "innerCircle" , "inner3") + remove!(p, "big_spline" , "inner1") end From 68376ebfc5d980572cffe5cb7a810ef7f64455e8 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 11:29:06 +0200 Subject: [PATCH 074/164] query getCurve incorrectly to throw a warning --- test/test_visualization.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 0311d6c9..8976641a 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -67,8 +67,12 @@ using CairoMakie [1.0 1.75 -1.0 0.0] ] spline2 = new("small_spline", 5, data) add!(p, spline2, "inner2") - + # # Test getting the inner curve and test + # + # Purposely get the names wrong to throw a warning + dict = getCurve(å, "small_spline", "inner1") + # Do it correctly this time dict = getCurve(p, "small_spline", "inner2") @test dict["TYPE"] == "SPLINE_CURVE" From 7c85d920f159b670bea2ca896fe4e60757d57d01 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 12:00:49 +0200 Subject: [PATCH 075/164] trigger warning of mismatched chain and boundary names in removal --- src/Project/ModelAPI.jl | 2 +- test/test_visualization.jl | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 9de93520..ebd3b6d4 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -218,7 +218,7 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin i, chain = getInnerBoundaryChainWithName(proj,chainName) lst = chain["LIST"] if isempty(lst) - println("No curve ", name, " in boundary ", chainName) #TODO Replace with error() + println("No curve ", name, " in boundary ", chainName, ". Try again.") return end indx = getChainIndex(lst,name) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 8976641a..4cf1be1d 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -112,6 +112,11 @@ using CairoMakie remove!(p, "outerCircle") # Remove the inner boundaries from the project + + # Purposely do this wrong to throw a warning + remove!(p, "big_spline" , "inner2") + + # Do the inner boudary removals correctly remove!(p, "small_spline", "inner2") remove!(p, "innerCircle" , "inner3") remove!(p, "big_spline" , "inner1") From dff4bc0157f34daa7d019041f99b0c0b89e51458 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 14:08:35 +0200 Subject: [PATCH 076/164] adjust logic in the removeInnerBoundaryCurve to be more robust and not mess with plotting --- src/Project/ModelAPI.jl | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index ebd3b6d4..50cbcf32 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -217,9 +217,27 @@ Remove the named curve in the inner boundary function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) i, chain = getInnerBoundaryChainWithName(proj,chainName) lst = chain["LIST"] + + # Go through `chainName` and check if the passed `name` is present in said chain + name_check = 0 + for (i,dict) in enumerate(lst) + if dict["name"] == name + name_check += 1 + end + end + if isempty(lst) - println("No curve ", name, " in boundary ", chainName, ". Try again.") - return + # When the chain is empty, `chainName` was not present before the call. + # Throw a warning and remove the empty chain otherwise plotting routine breaks. + ibChains = getAllInnerBoundaries(proj) + deleteat!(ibChains,i) + deleteat!(proj.innerBoundaryChainNames,i) + deleteat!(proj.innerBoundaryNames,i) + error("No curve ", name, " in boundary ", chainName, ". Try again.") + elseif name_check == 0 + # Situation where `chainName` already exists but the `name` to be deleted that + # was passed does not lie in that `chainName`. Simply throw a warning. + error("No curve ", name, " in boundary ", chainName, ". Try again.") end indx = getChainIndex(lst,name) removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) @@ -262,14 +280,17 @@ end """ removeInnerBoundary!(proj::Project, chainName::String) -Remove an entire inner boundary +Remove an entire inner boundary. Note, cannot undo(). """ function removeInnerBoundary!(proj::Project, chainName::String) i, crv = getInnerBoundaryChainWithName(proj, chainName) deleteat!(proj.innerBoundaryChainNames, i) deleteat!(proj.innerBoundaryPoints, i) + deleteat!(proj.innerBoundaryNames, i) ibChains = getAllInnerBoundaries(proj) deleteat!(ibChains,i) + proj.backgroundGridShouldUpdate = true + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end # # -------------------------------------------------------------------------------------- From 66989587637057094bc3d3cd47d51ad9df642d0b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 14:09:09 +0200 Subject: [PATCH 077/164] add tests for the error that is now thrown by remove for the inner boundary curves --- test/test_visualization.jl | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 4cf1be1d..2dc2d2be 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -44,8 +44,8 @@ using CairoMakie # To mesh, a background grid is needed addBackgroundGrid!(p, [0.6, 0.6, 0.0]) - # Set file format to ISM and corresponding output file names - setMeshFileFormat!(p, "ISM") + # Set file format to ISM-V2 and corresponding output file names + setMeshFileFormat!(p, "ISM-V2") meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) @@ -71,13 +71,13 @@ using CairoMakie # Test getting the inner curve and test # # Purposely get the names wrong to throw a warning - dict = getCurve(å, "small_spline", "inner1") + dict = getCurve(p, "small_spline", "inner1") # Do it correctly this time dict = getCurve(p, "small_spline", "inner2") @test dict["TYPE"] == "SPLINE_CURVE" - # Set file format to ISM-V2 (to exericise plotting routine) - setMeshFileFormat!(p, "ISM-V2") + # Set file format to ISM (to exericise plotting routine) + setMeshFileFormat!(p, "ISM") meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) @@ -90,9 +90,13 @@ using CairoMakie @test_nowarn remove_mesh!(p) addBackgroundGrid!(p, [0.6,0.6,0.0]) - # Add a final inner boundary - circ4 = new("innerCircle", [-2.0, -0.75, 0.0], 0.3, 0.0, 360.0, "degrees") - add!(p, circ4, "inner3") + # Add a final inner boundary that contains multiple links in the chain + edge1 = newEndPointsLineCurve("edge1", [-2.3, -1.0, 0.0], [-1.7, -1.0, 0.0]) + edge2 = newEndPointsLineCurve("edge2", [-1.7, -1.0, 0.0], [-2.0, -0.4, 0.0]) + edge3 = newEndPointsLineCurve("edge3", [-2.0, -0.4, 0.0], [-2.3, -1.0, 0.0]) + add!(p, edge1, "inner3") + add!(p, edge2, "inner3") + add!(p, edge3, "inner3") # Create a refinement center and add it with the generic method cent = newRefinementCenter("Center1", "smooth", [-1.25, -3.0, 0.0], 0.2, 1.0) @@ -111,15 +115,22 @@ using CairoMakie # Remove the outer boundary from the project remove!(p, "outerCircle") + # # Remove the inner boundaries from the project + # # Purposely do this wrong to throw a warning - remove!(p, "big_spline" , "inner2") - - # Do the inner boudary removals correctly + # (1) Give a wrong "new" inner boundary name + @test_throws ErrorException remove!(p, "big_spline", "wrongName") + # (2) Give the wrong inner boundary name that exists but does not contain "big_spline" + @test_throws ErrorException remove!(p, "big_spline", "inner2") + # (3) Give the correct combination and remove the inner boundary + remove!(p, "big_spline", "inner1") + + # Do the rest of the inner boudary removals correctly. To remove the inner boundary + # with multiple chains we use a different method remove!(p, "small_spline", "inner2") - remove!(p, "innerCircle" , "inner3") - remove!(p, "big_spline" , "inner1") + removeInnerBoundary!(p, "inner3") end From a4335b7cd8288ec38fcffe074f40f38e07905aa2 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 14:28:19 +0200 Subject: [PATCH 078/164] fix error message in the refinement regions API --- src/Project/ModelAPI.jl | 4 ++-- src/Project/RefinementRegionsAPI.jl | 3 +-- test/test_refinement.jl | 4 ++++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 50cbcf32..9379e06a 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -228,7 +228,7 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin if isempty(lst) # When the chain is empty, `chainName` was not present before the call. - # Throw a warning and remove the empty chain otherwise plotting routine breaks. + # Throw an error and remove the empty chain otherwise plotting routine breaks. ibChains = getAllInnerBoundaries(proj) deleteat!(ibChains,i) deleteat!(proj.innerBoundaryChainNames,i) @@ -236,7 +236,7 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin error("No curve ", name, " in boundary ", chainName, ". Try again.") elseif name_check == 0 # Situation where `chainName` already exists but the `name` to be deleted that - # was passed does not lie in that `chainName`. Simply throw a warning. + # was passed does not lie in that `chainName`. Throw an error. error("No curve ", name, " in boundary ", chainName, ". Try again.") end indx = getChainIndex(lst,name) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 4cb2cdb2..c85e14ec 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -206,8 +206,7 @@ there is none. The return value is a dictionary that represents the refinement r function getRefinementRegion(proj::Project, indx::Int) lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") if indx > length(lst) - printf("Index %i is larger than the number of refinement regions, %i", indx, length(lst)) - return nothing + error("Index ",indx," is larger than the number of refinement regions ", length(lst)) end return lst[indx] end diff --git a/test/test_refinement.jl b/test/test_refinement.jl index ba795ae5..30b14e13 100644 --- a/test/test_refinement.jl +++ b/test/test_refinement.jl @@ -146,6 +146,10 @@ using Test s = getRefinementRegion(p,1) @test getRefinementName(s) == "Center1" + # Test that an error is thrown if one requests a refinement region with + # with an index larger than the number of regions present in the project + @test_throws ErrorException getRefinementRegion(p, 3) + c2 = newRefinementCenter("middle","smooth",[2.0,3.0,4.0],0.6,3.0) insertRefinementRegion!(p,c2,2) lst = getAllRefinementRegions(p) From 87d3ef5183166859f6d9bdcebaa2dc208daddc36 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 14:38:06 +0200 Subject: [PATCH 079/164] fix error message bugs that used C style printing --- src/Project/RefinementRegionsAPI.jl | 3 +-- test/test_refinement.jl | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index c85e14ec..4bc6815a 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -237,8 +237,7 @@ function getRefinementRegion(proj::Project, name::String) return i,r end end - println("Refinement region with name %s not found",name) - return nothing + error("Refinement region with name ", name, " not found!") end # # -------------------------------------------------------------------------------------- diff --git a/test/test_refinement.jl b/test/test_refinement.jl index 30b14e13..0c0ea28c 100644 --- a/test/test_refinement.jl +++ b/test/test_refinement.jl @@ -146,11 +146,17 @@ using Test s = getRefinementRegion(p,1) @test getRefinementName(s) == "Center1" + # Query for a refinement region that does not exist. Throws an error. + @test_throws ErrorException (i,r) = getRefinementRegion(p, "Line100") + # Test that an error is thrown if one requests a refinement region with # with an index larger than the number of regions present in the project @test_throws ErrorException getRefinementRegion(p, 3) c2 = newRefinementCenter("middle","smooth",[2.0,3.0,4.0],0.6,3.0) + # Attempt to set an refinement type. Simply throws a warning to "Try again" + setRefinementType!(c2, "fancy") + insertRefinementRegion!(p,c2,2) lst = getAllRefinementRegions(p) @test length(lst) == 3 From 76e2f4726931fb7db18fcb876187619be6650730 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 16:10:49 +0200 Subject: [PATCH 080/164] add additional tests to fire the progressive plotting of project --- test/runtests.jl | 3 ++ test/test_hqmtool_project.jl | 4 --- test/test_project_with_viz.jl | 56 +++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 4 deletions(-) create mode 100644 test/test_project_with_viz.jl diff --git a/test/runtests.jl b/test/runtests.jl index 5936f4e8..bdad93a6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -68,6 +68,9 @@ include("test_hqmtool_demos.jl") # HQMTool project test routines include("test_hqmtool_project.jl") +# HQMTool project + visualzation test routines +include("test_project_with_viz.jl") + # Refinement test routines include("test_refinement.jl") diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 03118cc7..aca6076f 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -86,10 +86,6 @@ using Test new_lower_left = [-25.0, -10.0, 0.0] setBackgroundGridLowerLeft!(p, new_lower_left) @test isapprox( getBackgroundGridLowerLeft(p) , new_lower_left ) - # # Update the size of the background grid - # setBackgroundGridSize!(p, 2.5, 1.5, 1.0) - # new_sizes = [2.5, 1.5, 1.0] - # @test isapprox( getBackgroundGridSize(p) , new_sizes ) end diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl new file mode 100644 index 00000000..9204d116 --- /dev/null +++ b/test/test_project_with_viz.jl @@ -0,0 +1,56 @@ +module TestProjectAndVisualization + +using HOHQMesh +using Test + +# We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used +# as a testing backend for HQMTool's Makie-based visualization. +using CairoMakie + +@testset "Project with Visualization Tests" begin + + projectName = "fromScratch" + projectPath = "out" + + p = newProject(projectName, projectPath) + + # Bounding box uses box = [TOP, LEFT, BOTTOM, RIGHT] + bounds = [9.0, -8.0, -8.0, 8.0] + N = [16, 17, 1] + + # Lay the background grid and plot it + addBackgroundGrid!(p, bounds, N) + plotProject!(p, HOHQMesh.GRID) + + # Build the outer boundary chain and plot piece-by-piece + outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [5.0, 3.0, 0.0]) + add!(p, outer_line1) + outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") + add!(p, outer_arc) + outer_line2 = newEndPointsLineCurve("outerline2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) + add!(p, outer_line2) + + # Check the computed background grid against expected values + x_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] + y_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] + p.xGrid, p.yGrid = projectGrid(p) + + @test isapprox(p.xGrid, x_grid_control) + @test isapprox(p.yGrid, y_grid_control) + + # Build the inner pill-shaped boundary chain and plot it piece-by-piece + inner_line1 = newEndPointsLineCurve("innerLine1", [1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) + add!(p, inner_line1, "inner1") + inner_bottom_arc = newCircularArcCurve("innerBottomArc", [0.0, 3.0, 0.0], 1.0, 0.0, -180.0, "degrees") + add!(p, inner_bottom_arc, "inner1") + inner_line2 = newEndPointsLineCurve("innerLine2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) + add!(p, inner_line2, "inner1") + inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") + add!(p, inner_top_arc, "inner1") + + # Generate the mesh (automatically updates the plot) + @test_nowarn generate_mesh(p) + +end + +end #module \ No newline at end of file From d10da378b02d4b1bfbb842ce0dac912c26fb80c4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 18:56:32 +0200 Subject: [PATCH 081/164] add explicit set radius in order to trigger curveDidChange in the new test file --- test/test_project_with_viz.jl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 9204d116..faeafdd6 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -25,8 +25,10 @@ using CairoMakie # Build the outer boundary chain and plot piece-by-piece outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [5.0, 3.0, 0.0]) add!(p, outer_line1) - outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") - add!(p, outer_arc) + outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 0.0, 0.0, 180.0, "degrees") + add!(p, outer_arc) # fails because the radius is wrong + setArcRadius!(outer_arc, 5.0) + add!(p, outer_arc) # succeed with the proper radius outer_line2 = newEndPointsLineCurve("outerline2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) add!(p, outer_line2) @@ -45,8 +47,10 @@ using CairoMakie add!(p, inner_bottom_arc, "inner1") inner_line2 = newEndPointsLineCurve("innerLine2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) add!(p, inner_line2, "inner1") - inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") - add!(p, inner_top_arc, "inner1") + inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 0.0, 180.0, 0.0, "degrees") + add!(p, inner_top_arc, "inner1") # fails as the curves won't join + setArcRadius!(inner_top_arc, 1.0) + add!(p, inner_top_arc, "inner1") # succeed with the proper radius # Generate the mesh (automatically updates the plot) @test_nowarn generate_mesh(p) From 87a86bb4fbf1ba2feca02c9f2a4a34d563a8f872 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 4 Apr 2022 19:12:07 +0200 Subject: [PATCH 082/164] add refinement region to trigger auto plotting when it is not in the options --- test/test_project_with_viz.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index faeafdd6..54d72d68 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -52,6 +52,11 @@ using CairoMakie setArcRadius!(inner_top_arc, 1.0) add!(p, inner_top_arc, "inner1") # succeed with the proper radius + # Add in a refinement center and adjust its width manually + cent = newRefinementCenter("center1", "smooth", [0.0, -1.0, 0.0], 0.25, 1.0) + setRefinementWidth!(cent, 0.5) + add!(p, cent) + # Generate the mesh (automatically updates the plot) @test_nowarn generate_mesh(p) From 7ab1ba4a974f60fac24bfca46d3b87d6b91e6c8e Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Mon, 4 Apr 2022 17:57:41 -0700 Subject: [PATCH 083/164] Add undo to removeInnerBoundary Operation can now be undone. --- src/Project/ModelAPI.jl | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 9379e06a..71a13e34 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -280,16 +280,38 @@ end """ removeInnerBoundary!(proj::Project, chainName::String) -Remove an entire inner boundary. Note, cannot undo(). +Remove an entire inner boundary. """ function removeInnerBoundary!(proj::Project, chainName::String) i, crv = getInnerBoundaryChainWithName(proj, chainName) + registerWithUndoManager(proj,insertInnerBoundaryAtIndex!, + (chainName,i,crv,proj.innerBoundaryPoints[i],proj.innerBoundaryNames[i]), + "Remove Inner Boundary") + deleteat!(proj.innerBoundaryChainNames, i) deleteat!(proj.innerBoundaryPoints, i) deleteat!(proj.innerBoundaryNames, i) ibChains = getAllInnerBoundaries(proj) deleteat!(ibChains,i) - proj.backgroundGridShouldUpdate = true + + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) +end +""" + insertInnerBoundaryAtIndex!(proj::Project, chainName::String, indx::Int, chain::??) + +Insert an entire inner boundary. Primarily meant for undo operation. +""" +function insertInnerBoundaryAtIndex!(proj::Project, chainName::String, i::Int, chain::Dict{String, Any}, + bPoints::Vector{Any}, bNames::Vector{String}) + + lst = getAllInnerBoundaries(proj::Project) + insert!(lst,i,chain) + insert!(proj.innerBoundaryChainNames,i,chainName) + insert!(proj.innerBoundaryPoints,i,bPoints) + insert!(p.innerBoundaryNames,i,bNames) + registerWithUndoManager(proj,removeInnerBoundary!, + (chainName,), + "Remove Inner Boundary") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end # From e54bdebdea06f3dcf70514fb9df3d7e6e0b47a16 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 08:43:50 +0200 Subject: [PATCH 084/164] improve undo robustness and test it better --- src/Project/ModelAPI.jl | 35 +++++++++++++++-------------------- test/test_visualization.jl | 17 +++++++++++++++-- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 71a13e34..f8d37132 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -203,7 +203,6 @@ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundary push!(a,curvePoints(crv,defaultPlotPts)) end push!(proj.innerBoundaryNames[i],crv["name"]) - proj.backgroundGridShouldUpdate = true registerWithUndoManager(proj,removeInnerBoundaryCurve!, (crv["name"],boundaryName), "Add Inner Boundary Curve") @@ -244,14 +243,13 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin end function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, - indx::Int, boundaryName::String) + indx::Int, boundaryName::String) i, chain = getInnerBoundaryChainWithName(proj,boundaryName) lst = chain["LIST"] insert!(lst,indx,crv) innerBoundaryPoints = proj.innerBoundaryPoints[i] insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) insert!(proj.innerBoundaryNames[i],indx,crv["name"]) - proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end @@ -260,20 +258,18 @@ function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::S lst = chain["LIST"] if indx > 0 crv = lst[indx] - deleteat!(lst,indx) - deleteat!(proj.innerBoundaryNames[i],indx) - deleteat!(proj.innerBoundaryPoints[i],indx) - registerWithUndoManager(proj,insertInnerBoundaryCurveAtIndex!, - (crv,indx,chainName), - "Remove Inner Boundary Curve") - if isempty(lst) - ibChains = getAllInnerBoundaries(proj) - deleteat!(ibChains,i) - deleteat!(proj.innerBoundaryChainNames,i) - deleteat!(proj.innerBoundaryPoints,i) - deleteat!(proj.innerBoundaryNames,i) + deleteat!(lst, indx) + if isempty(lst) # Boundary chain contained a single curve + # Complete removal. Requires a different function to be posted + # in the Undo Manager + removeInnerBoundary!(proj::Project, chainName::String) + else # Boundary chain contained more than one curve + deleteat!(proj.innerBoundaryNames[i],indx) + deleteat!(proj.innerBoundaryPoints[i],indx) + registerWithUndoManager(proj,insertInnerBoundaryCurveAtIndex!, + (crv,indx,chainName), + "Remove Inner Boundary Curve") end - proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end end @@ -293,7 +289,6 @@ function removeInnerBoundary!(proj::Project, chainName::String) deleteat!(proj.innerBoundaryNames, i) ibChains = getAllInnerBoundaries(proj) deleteat!(ibChains,i) - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -301,14 +296,14 @@ end Insert an entire inner boundary. Primarily meant for undo operation. """ -function insertInnerBoundaryAtIndex!(proj::Project, chainName::String, i::Int, chain::Dict{String, Any}, +function insertInnerBoundaryAtIndex!(proj::Project, chainName::String, i::Int, chain::Dict{String, Any}, bPoints::Vector{Any}, bNames::Vector{String}) - + lst = getAllInnerBoundaries(proj::Project) insert!(lst,i,chain) insert!(proj.innerBoundaryChainNames,i,chainName) insert!(proj.innerBoundaryPoints,i,bPoints) - insert!(p.innerBoundaryNames,i,bNames) + insert!(proj.innerBoundaryNames,i,bNames) registerWithUndoManager(proj,removeInnerBoundary!, (chainName,), "Remove Inner Boundary") diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 2dc2d2be..885f9c63 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -126,11 +126,24 @@ using CairoMakie @test_throws ErrorException remove!(p, "big_spline", "inner2") # (3) Give the correct combination and remove the inner boundary remove!(p, "big_spline", "inner1") + @test length(p.innerBoundaryNames) == 2 - # Do the rest of the inner boudary removals correctly. To remove the inner boundary - # with multiple chains we use a different method + # Do the rest of the inner boudary removals correctly. remove!(p, "small_spline", "inner2") + @test length(p.innerBoundaryNames) == 1 + undo() + @test length(p.innerBoundaryNames) == 2 + redo() + + # Remove a single part of the chain with multiple curves + @test length(p.innerBoundaryNames[1]) == 3 + remove!(p, "edge2", "inner3") + @test length(p.innerBoundaryNames[1]) == 2 + undo() + # To remove the inner boundary with multiple chains we use a different method. removeInnerBoundary!(p, "inner3") + undo() + redo() end From 6db101bd25f644532675c05a025b554e628915fa Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 08:57:47 +0200 Subject: [PATCH 085/164] Add a true error when the control file SPLINE does not have the nKnots value --- src/ControlFile/ControlFileOperations.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index f4cfa25e..c4c05dfd 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -297,11 +297,7 @@ end function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) if !haskey(splineDict, "nKnots") - @warn "Spline block must define nKnots before SPLINE_DATA. Skipping..." - line = "" - while !occursin("end{SPLINE_DATA",line) #BUG This will read one too many lines - line = readline(f) - end + error("Spline block must define nKnots before SPLINE_DATA. Try again.") end knotString = splineDict["nKnots"] From c93c330fbbe1b7dca417c36ba949a33b4b157454 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 10:06:25 +0200 Subject: [PATCH 086/164] update action names for the outer boundary removal / insert --- src/HOHQMesh.jl | 2 +- src/Project/ModelAPI.jl | 11 ++++++----- test/test_model.jl | 6 +++--- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 13270b6c..4e57468a 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -90,7 +90,7 @@ export addCurveToOuterBoundary!, insertOuterBoundaryCurveAtIndex!, removeOuterBoundaryCurveAtIndex!, addOuterBoundary!, - removeOuterboundary!, + removeOuterBoundary!, getOuterBoundaryChainList, addCurveToInnerBoundary!, removeInnerBoundaryCurve!, diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index f8d37132..aa73fe67 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -58,7 +58,7 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) push!(proj.outerBndryNames,crv["name"]) - registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") + registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Outer Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -96,7 +96,7 @@ function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, insert!(proj.outerBndryPoints,indx,curvePoints(crv,defaultPlotPts)) insert!(proj.outerBndryNames,indx,crv["name"]) proj.backgroundGridShouldUpdate = true - registerWithUndoManager(proj,removeOuterBoundaryCurveAtIndex!,(indx,),"Add Curve") + registerWithUndoManager(proj,removeOuterBoundaryCurveAtIndex!,(indx,),"Add Outer Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end @@ -107,7 +107,7 @@ function removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) deleteat!(proj.outerBndryNames,indx) deleteat!(proj.outerBndryPoints,indx) proj.backgroundGridShouldUpdate = true - registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Add Curve") + registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Remove Outer Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ @@ -119,17 +119,18 @@ This function is only used as part of an undo operation removing the outer bound function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) model = getModelDict(proj) model["OUTER_BOUNDARY"] = outerBoundary - registerWithUndoManager(proj,removeOuterboundary!, (nothing,), "Add Outer Boundary") + registerWithUndoManager(proj,removeOuterBoundary!, (nothing,), "Add Outer Boundary") end """ removeOuterboundary!(proj::Project) Remove the outer boundary curve if it exists. """ -function removeOuterboundary!(proj::Project) +function removeOuterBoundary!(proj::Project) modelDict = getModelDict(proj) if haskey(modelDict,"OUTER_BOUNDARY") ob = modelDict["OUTER_BOUNDARY"] + println(ob) registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") delete!(modelDict,"OUTER_BOUNDARY") proj.outerBndryPoints = Any[] diff --git a/test/test_model.jl b/test/test_model.jl index 67478664..1c55dfd3 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -55,10 +55,10 @@ using Test obList = getOuterBoundaryChainList(p) @test length(obList) == 3 @test getChainIndex(obList,"obc3") == 3 - @test undoActionName() == "Add Curve" + @test undoActionName() == "Add Outer Boundary Curve" undo() @test length(obList) == 2 - @test redoActionName() == "Add Curve" + @test redoActionName() == "Remove Outer Boundary Curve" redo() @test length(obList) == 3 @@ -67,7 +67,7 @@ using Test # # Test remove/add outer boundary # - removeOuterboundary!(p) + removeOuterBoundary!(p) mDict = getModelDict(p) @test haskey(mDict,"OUTER_BOUNDARY") == false undo() From 738fcc5adbf58f3fcd665d4820ad1f186a30e02d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 10:30:42 +0200 Subject: [PATCH 087/164] bug fix in addOuterBoundary, now undo() works properly plus plots and posts notification --- src/Project/ModelAPI.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index aa73fe67..45df6360 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -118,8 +118,18 @@ This function is only used as part of an undo operation removing the outer bound """ function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) model = getModelDict(proj) + # Recover the complete outer boundary dictionary model["OUTER_BOUNDARY"] = outerBoundary + # Recover the outer boundary points and names for each member of the chain (necessary for plotting) + chain = getOuterBoundaryChainList(proj) + for (i, crv) in enumerate(chain) + crvPoints = curvePoints(crv, defaultPlotPts) + push!(proj.outerBndryPoints, crvPoints) + push!(proj.outerBndryNames , crv["name"]) + end + proj.backgroundGridShouldUpdate = true registerWithUndoManager(proj,removeOuterBoundary!, (nothing,), "Add Outer Boundary") + postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end """ removeOuterboundary!(proj::Project) From 7b4536f6917b0ed17e5ac9cb944d3484affe1b75 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 10:41:58 +0200 Subject: [PATCH 088/164] small typo change --- src/Project/ModelAPI.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 45df6360..c9458492 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -70,8 +70,8 @@ function removeOuterBoundaryCurveWithName!(proj::Project, name::String) lst = getOuterBoundaryChainList(proj) indx = getChainIndex(lst,name) if indx > 0 - removeOuterBoundaryCurveAtIndex!(proj,indx) # posts undo/notification proj.backgroundGridShouldUpdate = true + removeOuterBoundaryCurveAtIndex!(proj,indx) # posts undo/notification end end """ @@ -114,7 +114,7 @@ end addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) Add an empty outer boundary to the project. There can be only one. -This function is only used as part of an undo operation removing the outer boundary +This function is only used as part of an undo operation removing the outer boundary. """ function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) model = getModelDict(proj) From 73cfc2ca11a023d43b15d65a801f84077b24db13 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 11:07:52 +0200 Subject: [PATCH 089/164] move lines around in the printing --- src/HOHQMesh.jl | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 4e57468a..7cd6ede1 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -328,8 +328,8 @@ function run_demo(folder::String; called_by_user=true) p = openProject(all_features_control_file, folder) plotProject!(p, MODEL+REFINEMENTS+GRID) + println("Press enter to continue and generate the mesh") if called_by_user - println("Press enter to continue and generate the mesh") readline() end generate_mesh(p) @@ -365,13 +365,12 @@ function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # To mesh, a background grid is needed # addBackgroundGrid!(p, [0.5,0.5,0.0]) - - plotProject!(p, MODEL+GRID) - if called_by_user # # Show the model and grid # - println("Press enter to continue and generate the mesh") + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + if called_by_user readline() end # @@ -412,16 +411,14 @@ function ice_cream_cone_demo(folder::String; called_by_user=true) setMeshFileFormat!(p, "ABAQUS") meshFileFormat = getMeshFileFormat(p) setFileNames!(p, meshFileFormat) - - plotProject!(p, MODEL+GRID) - if called_by_user # # Show the model and grid # - println("Press enter to continue and generate the mesh") + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + if called_by_user readline() end - # # Generate the mesh and plot # From 2f460af52578bd7c3add64777eb481a85e786cdb Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 11:21:12 +0200 Subject: [PATCH 090/164] exercise empty undo/redo outputs --- test/test_model.jl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/test_model.jl b/test/test_model.jl index 1c55dfd3..62e54e6f 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -35,6 +35,14 @@ using Test @testset "Model Tests" begin # +# Exercise the different outputs for empty undo / redo stacks +# + clearUndoRedo() + @test undo() == "Empty undo stack. No action performed." + @test undoActionName() == "No undo action in queue" + @test redo() == "Empty redo stack. No action performed." + @test redoActionName() == "No redo action in queue" +# # Project for the model # projectName = "TestProject" From 3a6a4ed245c384d238e9250a072112c08f6f3e69 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 11:42:46 +0200 Subject: [PATCH 091/164] remove extraneous logic in curve point(s) computation --- src/Curves/CurveOperations.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index cbc261c7..b81ede7f 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -184,8 +184,6 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) end splineCurvePoints(nKnots,splineData,x) - else - end return x end @@ -227,8 +225,6 @@ function curvePoint(crvDict::Dict{String,Any}, t::Float64) splineData = crvDict["SPLINE_DATA"] x = zeros(Float64,3) splineCurvePoint(nKnots,splineData,t,x) - else - end return x end From 4fe6a5d1bcd4d2b3fa1727765b88a4a4f613f868 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 11:52:43 +0200 Subject: [PATCH 092/164] throw error is parametric equation does not have an equal sign --- src/Misc/DictionaryOperations.jl | 34 ++++++++++++++++---------------- test/test_curve.jl | 4 ++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index 96bbc960..15f91daa 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -31,17 +31,17 @@ arrayRegex = r"(?<=\[).+?(?=\])" function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] - return parse(Float64,v) + return parse(Float64,v) end function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] - return parse(Int64,v) + return parse(Int64,v) end function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] - return v + return v end function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) @@ -63,7 +63,7 @@ end function keyAndValueFromString(s) indxOfEqual = findfirst("=",s) if indxOfEqual === nothing - return nothing + error("Equal sign = required to distinguish key and value from a string.") end key = strip(s[1:indxOfEqual.start-1],[' ','\t']) value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) diff --git a/test/test_curve.jl b/test/test_curve.jl index 1c48e947..fa97f584 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -80,6 +80,10 @@ using Test @test getXEqn(crv) == "t^2" @test getYEqn(crv) == "1.5*t" @test getZEqn(crv) == "t^3" + + # If the equal sign is forgotten an error is thrown + fEqn = "f(t) 1.5*t" + @test_throws ErrorException HOHQMesh.keyAndValueFromString(fEqn) end @testset "EndPointLine Tests" begin From 72b3ef9fc2f22689eca9d940a4b1120d2727a9a3 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 12:04:55 +0200 Subject: [PATCH 093/164] remove extraneous logic from refinementDidChange because the plot options are already updated in refinementWasAdded --- src/Project/Project.jl | 55 ++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 48642fd5..e4c9ea19 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# #= @@ -90,7 +90,7 @@ function openProject(fileName::String, folder::String) # Overwrite defaults # proj.projectDictionary = controlDict - + assemblePlotArrays(proj) clearUndoRedo() @@ -135,7 +135,7 @@ function newProject(name::String, folder::String) plotOptions = 0 # proj = Project(name, folder, projectDict, plt, plotOptions, obPnts, obNames, - ibChainPoints,ibNames, ibChainNames, + ibChainPoints,ibNames, ibChainNames, refinementRegionPts,refinementRegionNames, refinementRegionLocs, bounds, userBounds, xGrid, yGrid, xMesh, yMesh, true, false) @@ -171,7 +171,7 @@ function hasBackgroundGrid(proj::Project) end function assemblePlotArrays(proj::Project) - + empty!(proj.outerBndryPoints) empty!(proj.outerBndryNames) empty!(proj.innerBoundaryChainNames) @@ -179,7 +179,7 @@ function assemblePlotArrays(proj::Project) empty!(proj.innerBoundaryNames) empty!(proj.xGrid) empty!(proj.yGrid) - + bounds = emptyBounds() modelDict = getModelDict(proj) @@ -194,11 +194,11 @@ function assemblePlotArrays(proj::Project) for crv in obChain push!(proj.outerBndryNames,crv["name"]) - end + end end if haskey(modelDict,"INNER_BOUNDARIES") - innerBoundaries = modelDict["INNER_BOUNDARIES"] + innerBoundaries = modelDict["INNER_BOUNDARIES"] innerBoundaryList = innerBoundaries["LIST"] #LIST of CHAINS for d in innerBoundaryList push!(proj.innerBoundaryChainNames, d["name"]) @@ -222,7 +222,7 @@ function assemblePlotArrays(proj::Project) refinementsList = refinementBlock["LIST"] for ref in refinementsList addRefinementRegionPoints!(proj,ref) - end + end end proj.bounds = bounds end @@ -303,11 +303,11 @@ function curveDidChange(proj::Project,crv::Dict{String,Any}) proj.outerBndryPoints[i] = curvePoints(crv,defaultPlotPts) if !isnothing(proj.plt) options = proj.plotOptions - updatePlot!(proj, options) + updatePlot!(proj, options) end return nothing end - end + end # # Otherwise, see if it is an inner boundary # @@ -321,13 +321,13 @@ function curveDidChange(proj::Project,crv::Dict{String,Any}) if !isnothing(proj.plt) options = proj.plotOptions - updatePlot!(proj, options) + updatePlot!(proj, options) end return nothing end function modelDidChange(proj::Project, sender::Project) - + if proj === sender && !isnothing(proj.plt) options = proj.plotOptions if (options & MODEL) == 0 @@ -367,7 +367,7 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) indx = i break end - end + end if indx > 0 x = refinementRegionPoints(sender) @@ -375,12 +375,9 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) proj.refinementRegionNames[indx] = sender["name"] center = getRefinementRegionCenter(sender) proj.refinementRegionLoc[indx] = center - + if !isnothing(proj.plt) options = proj.plotOptions - if (options & REFINEMENTS) == 0 - options = options + REFINEMENTS - end updatePlot!(proj, options) end else From b96977ca4037e313ad7090a15579b51e699bdf7c Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 13:47:00 +0200 Subject: [PATCH 094/164] adjust visualization tests. Should cover special logic for automatic plot updates --- test/test_project_with_viz.jl | 47 +++++++++--------- test/test_visualization.jl | 90 +++++++++++++++++------------------ 2 files changed, 68 insertions(+), 69 deletions(-) diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 54d72d68..253bf57e 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -7,58 +7,57 @@ using Test # as a testing backend for HQMTool's Makie-based visualization. using CairoMakie -@testset "Project with Visualization Tests" begin +@testset "Project with Visualization Tests (from scratch)" begin projectName = "fromScratch" projectPath = "out" - p = newProject(projectName, projectPath) + p_scratch = newProject(projectName, projectPath) # Bounding box uses box = [TOP, LEFT, BOTTOM, RIGHT] bounds = [9.0, -8.0, -8.0, 8.0] N = [16, 17, 1] # Lay the background grid and plot it - addBackgroundGrid!(p, bounds, N) - plotProject!(p, HOHQMesh.GRID) + addBackgroundGrid!(p_scratch, bounds, N) + plotProject!(p_scratch, HOHQMesh.GRID) # Build the outer boundary chain and plot piece-by-piece - outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [5.0, 3.0, 0.0]) - add!(p, outer_line1) - outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 0.0, 0.0, 180.0, "degrees") - add!(p, outer_arc) # fails because the radius is wrong - setArcRadius!(outer_arc, 5.0) - add!(p, outer_arc) # succeed with the proper radius + outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [4.0, 3.0, 0.0]) + add!(p_scratch, outer_line1) + # Update the endpoint to trigger update plot from `curveDidChange` + setEndPoint!(outer_line1, [5.0, 3.0, 0.0]) + outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") + add!(p_scratch, outer_arc) outer_line2 = newEndPointsLineCurve("outerline2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) - add!(p, outer_line2) + add!(p_scratch, outer_line2) # Check the computed background grid against expected values x_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] y_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] - p.xGrid, p.yGrid = projectGrid(p) + p_scratch.xGrid, p_scratch.yGrid = projectGrid(p_scratch) - @test isapprox(p.xGrid, x_grid_control) - @test isapprox(p.yGrid, y_grid_control) + @test isapprox(p_scratch.xGrid, x_grid_control) + @test isapprox(p_scratch.yGrid, y_grid_control) # Build the inner pill-shaped boundary chain and plot it piece-by-piece - inner_line1 = newEndPointsLineCurve("innerLine1", [1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) - add!(p, inner_line1, "inner1") + inner_line1 = newEndPointsLineCurve("innerLine1", [-1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) + add!(p_scratch, inner_line1, "inner1") + setStartPoint!(inner_line1, [1.0, 5.0, 0.0]) inner_bottom_arc = newCircularArcCurve("innerBottomArc", [0.0, 3.0, 0.0], 1.0, 0.0, -180.0, "degrees") - add!(p, inner_bottom_arc, "inner1") + add!(p_scratch, inner_bottom_arc, "inner1") inner_line2 = newEndPointsLineCurve("innerLine2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) - add!(p, inner_line2, "inner1") - inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 0.0, 180.0, 0.0, "degrees") - add!(p, inner_top_arc, "inner1") # fails as the curves won't join - setArcRadius!(inner_top_arc, 1.0) - add!(p, inner_top_arc, "inner1") # succeed with the proper radius + add!(p_scratch, inner_line2, "inner1") + inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") + add!(p_scratch, inner_top_arc, "inner1") # Add in a refinement center and adjust its width manually cent = newRefinementCenter("center1", "smooth", [0.0, -1.0, 0.0], 0.25, 1.0) + add!(p_scratch, cent) setRefinementWidth!(cent, 0.5) - add!(p, cent) # Generate the mesh (automatically updates the plot) - @test_nowarn generate_mesh(p) + @test_nowarn generate_mesh(p_scratch) end diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 885f9c63..e31ed7a6 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -21,43 +21,43 @@ using CairoMakie projectName = "CirclesInCircle" projectPath = "out" - p = newProject(projectName, projectPath) + p_visu = newProject(projectName, projectPath) # Outer boundary circ = new("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") - add!(p, circ) + add!(p_visu, circ) # Test getting the outer curve name - dict = getCurve(p, "outerCircle") + dict = getCurve(p_visu, "outerCircle") @test dict["TYPE"] == "CIRCULAR_ARC" # First inner boundary via a spline from a file spline1 = new("big_spline", joinpath(@__DIR__, "test_spline_curve_data.txt")) - add!(p, spline1, "inner1") + add!(p_visu, spline1, "inner1") # Test extracting an inner boundary chain with the generic function - tup = getInnerBoundary(p, "inner1") + tup = getInnerBoundary(p_visu, "inner1") @test tup[2]["TYPE"] == "CHAIN" # Attempt to generate the mesh before the background grid is set. Throws an error. - @test_nowarn generate_mesh(p) + @test_nowarn generate_mesh(p_visu) # To mesh, a background grid is needed - addBackgroundGrid!(p, [0.6, 0.6, 0.0]) + addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) # Set file format to ISM-V2 and corresponding output file names - setMeshFileFormat!(p, "ISM-V2") - meshFileFormat = getMeshFileFormat(p) - setFileNames!(p, meshFileFormat) + setMeshFileFormat!(p_visu, "ISM-V2") + meshFileFormat = getMeshFileFormat(p_visu) + setFileNames!(p_visu, meshFileFormat) # Show initial the model and grid - @test_nowarn plotProject!(p, HOHQMesh.MODEL + HOHQMesh.GRID) + @test_nowarn plotProject!(p_visu, HOHQMesh.MODEL + HOHQMesh.GRID) # Create the mesh which contains a plotting update for ISM - @test_nowarn generate_mesh(p) + @test_nowarn generate_mesh(p_visu) # Destroy the mesh and reset the background grid - @test_nowarn remove_mesh!(p) - addBackgroundGrid!(p, [0.6,0.6,0.0]) + @test_nowarn remove_mesh!(p_visu) + addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) # Add another inner boundary via a spline with given data points data = [ [0.0 1.75 -1.0 0.0] @@ -66,54 +66,54 @@ using CairoMakie [0.75 0.6 -2.0 0.0] [1.0 1.75 -1.0 0.0] ] spline2 = new("small_spline", 5, data) - add!(p, spline2, "inner2") + add!(p_visu, spline2, "inner2") # # Test getting the inner curve and test # # Purposely get the names wrong to throw a warning - dict = getCurve(p, "small_spline", "inner1") + dict = getCurve(p_visu, "small_spline", "inner1") # Do it correctly this time - dict = getCurve(p, "small_spline", "inner2") + dict = getCurve(p_visu, "small_spline", "inner2") @test dict["TYPE"] == "SPLINE_CURVE" # Set file format to ISM (to exericise plotting routine) - setMeshFileFormat!(p, "ISM") - meshFileFormat = getMeshFileFormat(p) - setFileNames!(p, meshFileFormat) + setMeshFileFormat!(p_visu, "ISM") + meshFileFormat = getMeshFileFormat(p_visu) + setFileNames!(p_visu, meshFileFormat) - @test_nowarn updatePlot!(p) + @test_nowarn updatePlot!(p_visu) # Create the mesh which contains a plotting update for ISM-V2 - @test_nowarn generate_mesh(p) + @test_nowarn generate_mesh(p_visu) # Destroy the mesh and reset the background grid - @test_nowarn remove_mesh!(p) - addBackgroundGrid!(p, [0.6,0.6,0.0]) + @test_nowarn remove_mesh!(p_visu) + addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) # Add a final inner boundary that contains multiple links in the chain edge1 = newEndPointsLineCurve("edge1", [-2.3, -1.0, 0.0], [-1.7, -1.0, 0.0]) edge2 = newEndPointsLineCurve("edge2", [-1.7, -1.0, 0.0], [-2.0, -0.4, 0.0]) edge3 = newEndPointsLineCurve("edge3", [-2.0, -0.4, 0.0], [-2.3, -1.0, 0.0]) - add!(p, edge1, "inner3") - add!(p, edge2, "inner3") - add!(p, edge3, "inner3") + add!(p_visu, edge1, "inner3") + add!(p_visu, edge2, "inner3") + add!(p_visu, edge3, "inner3") # Create a refinement center and add it with the generic method cent = newRefinementCenter("Center1", "smooth", [-1.25, -3.0, 0.0], 0.2, 1.0) - add!(p, cent) + add!(p_visu, cent) # Set file format to ABAQUS (to exericise plotting routine) - setMeshFileFormat!(p, "ABAQUS") - meshFileFormat = getMeshFileFormat(p) - setFileNames!(p, meshFileFormat) + setMeshFileFormat!(p_visu, "ABAQUS") + meshFileFormat = getMeshFileFormat(p_visu) + setFileNames!(p_visu, meshFileFormat) - @test_nowarn updatePlot!(p, HOHQMesh.MODEL + HOHQMesh.GRID + HOHQMesh.REFINEMENTS) + @test_nowarn updatePlot!(p_visu, HOHQMesh.MODEL + HOHQMesh.GRID + HOHQMesh.REFINEMENTS) # Create the mesh which contains a plotting update for ABAQUS - @test_nowarn generate_mesh(p) + @test_nowarn generate_mesh(p_visu) # Remove the outer boundary from the project - remove!(p, "outerCircle") + remove!(p_visu, "outerCircle") # # Remove the inner boundaries from the project @@ -121,27 +121,27 @@ using CairoMakie # Purposely do this wrong to throw a warning # (1) Give a wrong "new" inner boundary name - @test_throws ErrorException remove!(p, "big_spline", "wrongName") + @test_throws ErrorException remove!(p_visu, "big_spline", "wrongName") # (2) Give the wrong inner boundary name that exists but does not contain "big_spline" - @test_throws ErrorException remove!(p, "big_spline", "inner2") + @test_throws ErrorException remove!(p_visu, "big_spline", "inner2") # (3) Give the correct combination and remove the inner boundary - remove!(p, "big_spline", "inner1") - @test length(p.innerBoundaryNames) == 2 + remove!(p_visu, "big_spline", "inner1") + @test length(p_visu.innerBoundaryNames) == 2 # Do the rest of the inner boudary removals correctly. - remove!(p, "small_spline", "inner2") - @test length(p.innerBoundaryNames) == 1 + remove!(p_visu, "small_spline", "inner2") + @test length(p_visu.innerBoundaryNames) == 1 undo() - @test length(p.innerBoundaryNames) == 2 + @test length(p_visu.innerBoundaryNames) == 2 redo() # Remove a single part of the chain with multiple curves - @test length(p.innerBoundaryNames[1]) == 3 - remove!(p, "edge2", "inner3") - @test length(p.innerBoundaryNames[1]) == 2 + @test length(p_visu.innerBoundaryNames[1]) == 3 + remove!(p_visu, "edge2", "inner3") + @test length(p_visu.innerBoundaryNames[1]) == 2 undo() # To remove the inner boundary with multiple chains we use a different method. - removeInnerBoundary!(p, "inner3") + removeInnerBoundary!(p_visu, "inner3") undo() redo() From c2efc1678ba9fad8fdfe0077a759f0bfd38846fa Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 14:05:47 +0200 Subject: [PATCH 095/164] add another test for the visualization logic --- src/Project/Project.jl | 9 ++- test/test_project_with_viz.jl | 124 ++++++++++++++++++++-------------- 2 files changed, 80 insertions(+), 53 deletions(-) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index e4c9ea19..c8c6b468 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -378,10 +378,15 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) if !isnothing(proj.plt) options = proj.plotOptions + if (options & REFINEMENTS) == 0 + options = options + REFINEMENTS + end updatePlot!(proj, options) end - else - println("Refinement region with name $regionName not found.") + # TODO: Remove this? It triggers to the screen frequently during example that work + # correctly. Not sure why it is here. + # else + # println("Refinement region with name $regionName not found.") end end diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 253bf57e..e6e18521 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -7,58 +7,80 @@ using Test # as a testing backend for HQMTool's Makie-based visualization. using CairoMakie -@testset "Project with Visualization Tests (from scratch)" begin - - projectName = "fromScratch" - projectPath = "out" - - p_scratch = newProject(projectName, projectPath) - - # Bounding box uses box = [TOP, LEFT, BOTTOM, RIGHT] - bounds = [9.0, -8.0, -8.0, 8.0] - N = [16, 17, 1] - - # Lay the background grid and plot it - addBackgroundGrid!(p_scratch, bounds, N) - plotProject!(p_scratch, HOHQMesh.GRID) - - # Build the outer boundary chain and plot piece-by-piece - outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [4.0, 3.0, 0.0]) - add!(p_scratch, outer_line1) - # Update the endpoint to trigger update plot from `curveDidChange` - setEndPoint!(outer_line1, [5.0, 3.0, 0.0]) - outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") - add!(p_scratch, outer_arc) - outer_line2 = newEndPointsLineCurve("outerline2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) - add!(p_scratch, outer_line2) - - # Check the computed background grid against expected values - x_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] - y_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] - p_scratch.xGrid, p_scratch.yGrid = projectGrid(p_scratch) - - @test isapprox(p_scratch.xGrid, x_grid_control) - @test isapprox(p_scratch.yGrid, y_grid_control) - - # Build the inner pill-shaped boundary chain and plot it piece-by-piece - inner_line1 = newEndPointsLineCurve("innerLine1", [-1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) - add!(p_scratch, inner_line1, "inner1") - setStartPoint!(inner_line1, [1.0, 5.0, 0.0]) - inner_bottom_arc = newCircularArcCurve("innerBottomArc", [0.0, 3.0, 0.0], 1.0, 0.0, -180.0, "degrees") - add!(p_scratch, inner_bottom_arc, "inner1") - inner_line2 = newEndPointsLineCurve("innerLine2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) - add!(p_scratch, inner_line2, "inner1") - inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") - add!(p_scratch, inner_top_arc, "inner1") - - # Add in a refinement center and adjust its width manually - cent = newRefinementCenter("center1", "smooth", [0.0, -1.0, 0.0], 0.25, 1.0) - add!(p_scratch, cent) - setRefinementWidth!(cent, 0.5) - - # Generate the mesh (automatically updates the plot) - @test_nowarn generate_mesh(p_scratch) +@testset "Project with Visualization Tests" begin + @testset "Project From Scratch" begin + projectName = "fromScratch" + projectPath = "out" + + p_scratch = newProject(projectName, projectPath) + + # Bounding box uses box = [TOP, LEFT, BOTTOM, RIGHT] + bounds = [9.0, -8.0, -8.0, 8.0] + N = [16, 17, 1] + + # Lay the background grid and plot it + addBackgroundGrid!(p_scratch, bounds, N) + plotProject!(p_scratch, HOHQMesh.GRID) + + # Build the outer boundary chain and plot piece-by-piece + outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [4.0, 3.0, 0.0]) + add!(p_scratch, outer_line1) + # Update the endpoint to trigger update plot from `curveDidChange` + setEndPoint!(outer_line1, [5.0, 3.0, 0.0]) + outer_arc = newCircularArcCurve("outerarc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") + add!(p_scratch, outer_arc) + outer_line2 = newEndPointsLineCurve("outerline2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) + add!(p_scratch, outer_line2) + + # Check the computed background grid against expected values + x_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] + y_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] + p_scratch.xGrid, p_scratch.yGrid = projectGrid(p_scratch) + + @test isapprox(p_scratch.xGrid, x_grid_control) + @test isapprox(p_scratch.yGrid, y_grid_control) + + # Build the inner pill-shaped boundary chain and plot it piece-by-piece + inner_line1 = newEndPointsLineCurve("innerLine1", [-1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) + add!(p_scratch, inner_line1, "inner1") + setStartPoint!(inner_line1, [1.0, 5.0, 0.0]) + inner_bottom_arc = newCircularArcCurve("innerBottomArc", [0.0, 3.0, 0.0], 1.0, 0.0, -180.0, "degrees") + add!(p_scratch, inner_bottom_arc, "inner1") + inner_line2 = newEndPointsLineCurve("innerLine2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) + add!(p_scratch, inner_line2, "inner1") + inner_top_arc = newCircularArcCurve("innerTopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") + add!(p_scratch, inner_top_arc, "inner1") + + # Add in a refinement center and adjust its width manually + cent = newRefinementCenter("center1", "smooth", [0.0, -1.0, 0.0], 0.25, 1.0) + add!(p_scratch, cent) + setRefinementWidth!(cent, 0.5) + + # Generate the mesh (automatically updates the plot) + @test_nowarn generate_mesh(p_scratch) + + end + + @testset "Project From File" begin + + projectPath = "out" + + control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") + p_file = openProject(control_file, projectPath) + + @test_nowarn plotProject!(p_file, HOHQMesh.MODEL + HOHQMesh.GRID) + + # Refinement regions are already present but we manually adjust + # one of its parameters to trigger a specific piece of plot update logic + _, refine_center = getRefinementRegion(p_file, "center") + setRefinementGridSize!(refine_center, 0.15) + @test getRefinementGridSize(refine_center) == 0.15 + + # Generate the mesh (automatically updates the plot) + @test_nowarn generate_mesh(p_file) + + end end end #module \ No newline at end of file From a2e7c0b5db8f9e1c07146fc4d5a3256252df549a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 14:14:58 +0200 Subject: [PATCH 096/164] added test for updating the background grid size --- src/Project/BackgroundGridAPI.jl | 6 +++--- test/test_project_with_viz.jl | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index af9fe849..a85a5411 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -205,7 +205,7 @@ function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) return nothing end """ -setBackgroundGridSteps!(proj::Project, N::Array{Int}) + setBackgroundGridSteps!(proj::Project, N::Array{Int}) Set how many steps of size setBackgroundGridSpacing in each direction the background grid extends from the lower left. @@ -226,14 +226,14 @@ function setBackgroundGridSteps!(proj::Project, N::Array{Int}) return nothing end """ -setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) + setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) """ function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) setBackgroundGridSize!(proj, dx[1], dx[2], key) return nothing end """ -setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) + setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) """ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index e6e18521..14da145a 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -77,6 +77,10 @@ using CairoMakie setRefinementGridSize!(refine_center, 0.15) @test getRefinementGridSize(refine_center) == 0.15 + # Adjust the background grid size + setBackgroundGridSize!(p_file, 4.0, 4.0, 0.0) + @test getBackgroundGridSize(p_file) == [4.0, 4.0, 0.0] + # Generate the mesh (automatically updates the plot) @test_nowarn generate_mesh(p_file) From 89b79a5d5230be1ba95b4fda2396304dcc7658d8 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 14:23:39 +0200 Subject: [PATCH 097/164] add proper error throwing for the background grid queries --- src/Project/BackgroundGridAPI.jl | 6 +++--- test/test_visualization.jl | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index a85a5411..35bb44a8 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -154,7 +154,7 @@ function getBackgroundGridSize(proj::Project) elseif haskey(bgDict,"background grid size") return realArrayForKeyFromDictionary("background grid size",bgDict) else - return nothing + error("No background grid size is present.") end end """ @@ -167,7 +167,7 @@ function getBackgroundGridLowerLeft(proj::Project) if haskey(bgDict,"x0") return realArrayForKeyFromDictionary("x0",bgDict) else - return nothing + error("No background grid initial point x0 is present.") end end """ @@ -180,7 +180,7 @@ function getBackgroundGridSteps(proj::Project) if haskey(bgDict,"N") return intArrayForKeyFromDictionary("N",bgDict) else - return nothing + error("No background grid step size is present.") end end """ diff --git a/test/test_visualization.jl b/test/test_visualization.jl index e31ed7a6..61890b9c 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -41,6 +41,12 @@ using CairoMakie # Attempt to generate the mesh before the background grid is set. Throws an error. @test_nowarn generate_mesh(p_visu) + # There is no background grid. Query the different styles of background grids + # to test that errors are thrown correctly. + @test_throws ErrorException getBackgroundGridSize(p_visu) + @test_throws ErrorException getBackgroundGridLowerLeft(p_visu) + @test_throws ErrorException getBackgroundGridSteps(p_visu) + # To mesh, a background grid is needed addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) From bad63211951d5dc747f704050057739535755cdb Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 5 Apr 2022 19:49:51 +0200 Subject: [PATCH 098/164] small cleanup of the test files --- test/test_hqmtool_demos.jl | 6 ------ test/test_model.jl | 4 ++-- test/test_project_with_viz.jl | 3 ++- test/test_visualization.jl | 2 -- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/test/test_hqmtool_demos.jl b/test/test_hqmtool_demos.jl index cce837a1..133a925b 100644 --- a/test/test_hqmtool_demos.jl +++ b/test/test_hqmtool_demos.jl @@ -7,12 +7,6 @@ Functions: @ = tested @ hqmtool_ice_cream_cone_verbose_demo(folder::String) @ hqmtool_ice_cream_cone_demo(folder::String) =# - -# TODO: Fix this. Not sure how to handle the "Press any key" nonsense. -# Tests wont be very sophisticated, jsut a check that certain files are created -# -# somthing like this @test generate_mesh(control_file, verbose=true) isa String -# or this @test occursin("examples", HOHQMesh.examples_dir()) using HOHQMesh using Test diff --git a/test/test_model.jl b/test/test_model.jl index 62e54e6f..202c1903 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -35,7 +35,7 @@ using Test @testset "Model Tests" begin # -# Exercise the different outputs for empty undo / redo stacks +# Exercise the different outputs for empty undo / redo stacks # clearUndoRedo() @test undo() == "Empty undo stack. No action performed." @@ -108,7 +108,7 @@ using Test # # Purposely create outer / inner boundary curves that do -# not join in a new project. This will trigger error statements. +# not join in a new project. This will trigger warning statements. # obc1 = new("obc1",[0.0,0.0,0.0], [2.0,0.0,0.0]) obc2 = new("obc2",[3.0,0.0,0.0], [1.0,1.0,0.0]) diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 14da145a..e404fec3 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -15,7 +15,7 @@ using CairoMakie p_scratch = newProject(projectName, projectPath) - # Bounding box uses box = [TOP, LEFT, BOTTOM, RIGHT] + # Bounding box uses order [TOP, LEFT, BOTTOM, RIGHT] bounds = [9.0, -8.0, -8.0, 8.0] N = [16, 17, 1] @@ -73,6 +73,7 @@ using CairoMakie # Refinement regions are already present but we manually adjust # one of its parameters to trigger a specific piece of plot update logic + # in `refinementDidChange` _, refine_center = getRefinementRegion(p_file, "center") setRefinementGridSize!(refine_center, 0.15) @test getRefinementGridSize(refine_center) == 0.15 diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 61890b9c..0a52bc08 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -63,7 +63,6 @@ using CairoMakie # Destroy the mesh and reset the background grid @test_nowarn remove_mesh!(p_visu) - addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) # Add another inner boundary via a spline with given data points data = [ [0.0 1.75 -1.0 0.0] @@ -94,7 +93,6 @@ using CairoMakie # Destroy the mesh and reset the background grid @test_nowarn remove_mesh!(p_visu) - addBackgroundGrid!(p_visu, [0.6, 0.6, 0.0]) # Add a final inner boundary that contains multiple links in the chain edge1 = newEndPointsLineCurve("edge1", [-2.3, -1.0, 0.0], [-1.7, -1.0, 0.0]) From 8bb32493a9b1652b001f00c5e7c0a55e7bef1cb4 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 5 Apr 2022 12:48:31 -0700 Subject: [PATCH 099/164] Catch a typo in the plotProject! function name. --- docs/src/HQMTool.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 783a225a..56d9e3ab 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -142,7 +142,7 @@ To create generate a mesh you - To [visualize](#Plotting) the project's model, - plotProject(p,MODEL) + plotProject!(p,MODEL) To update the plot at any time, use @@ -166,7 +166,7 @@ To create generate a mesh you generateMesh(p) -The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject` command. +The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` command. ## HQMTool API @@ -193,7 +193,7 @@ writes a control file to the folder designated when creating the new project. It #### Plotting a Project - plotProject(proj::Project, options) + plotProject!(proj::Project, options) The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show where [manual refinement](#ManualRefinement) is added. From 9c150b382f0143814865dd28dd697793d788af75 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 6 Apr 2022 13:55:03 +0200 Subject: [PATCH 100/164] comment out docstring of duplicateCurve --- src/Project/CurvesAPI.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 0af1ecd0..54d41d82 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -135,11 +135,11 @@ function newSplineCurve(name::String, dataFile::String) end return spline end -""" - duplicateCurve(crv::Dict{String,Any}, newName::String) - -Duplicate the given curve giving it the new name. -""" +#""" +# duplicateCurve(crv::Dict{String,Any}, newName::String) +# +#Duplicate the given curve giving it the new name. +#""" # function duplicateCurve(crv::Dict{String,Any}, newName::String) # disableNotifications() # disableUndo() From d3674fe134b2a5756c391d461c69b991ba5574e5 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 6 Apr 2022 14:51:17 +0200 Subject: [PATCH 101/164] add the unRegisterForNotification function back in and test it --- src/Misc/NotificationCenter.jl | 46 +++++++++++++++++----------------- test/test_background_grid.jl | 8 ++++++ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/Misc/NotificationCenter.jl b/src/Misc/NotificationCenter.jl index 97f9ca34..98561908 100644 --- a/src/Misc/NotificationCenter.jl +++ b/src/Misc/NotificationCenter.jl @@ -55,29 +55,29 @@ function addObserver(observer::Any, note::String, fnction::Any) push!(HQMNotificationCenter[note],noteObj) end -# This is unused. We never remove notifications -# """ -# unRegisterForNotification(observer::Any, note::String) - -# Remove the observer from being notified by the notification `note` -# """ -# function unRegisterForNotification(observer::Any, note::String) -# if haskey(HQMNotificationCenter,note) -# global observers = HQMNotificationCenter[note] - -# for i = 1:length(observers) -# global noteObj = observers[i] -# noteObserver = noteObj.observer -# if noteObserver === observer -# deleteat!(observers,i) -# break -# end -# end -# if isempty(observers) -# delete!(HQMNotificationCenter,note) -# end -# end -# end +""" + unRegisterForNotification(observer::Any, note::String) + +Remove the observer from being notified by the notification `note` +""" +function unRegisterForNotification(observer::Any, note::String) + if haskey(HQMNotificationCenter,note) + global observers = HQMNotificationCenter[note] + + for i = 1:length(observers) + global noteObj = observers[i] + noteObserver = noteObj.observer + if noteObserver === observer + deleteat!(observers,i) + break + end + end + if isempty(observers) + delete!(HQMNotificationCenter,note) + end + end +end + """ postNotificationWithName(sender::Any, name::String, userInfo::Tuple) diff --git a/test/test_background_grid.jl b/test/test_background_grid.jl index 79d080d8..1a18edec 100644 --- a/test/test_background_grid.jl +++ b/test/test_background_grid.jl @@ -69,6 +69,14 @@ using Test removeBackgroundGrid!(p) @test hasBackgroundGrid(p) == false +# +# There are no longer any background grid. Delete the notification center piece as well. +# Note that the notification center is global and can have multiple observers. So we test +# this notification center removal before other observers are created that will add in the +# background grid again. +# + HOHQMesh.unRegisterForNotification(p, "BGRID_DID_CHANGE_NOTIFICATION") + @test haskey( HOHQMesh.HQMNotificationCenter , "BGRID_DID_CHANGE_NOTIFICATION" ) == false end From 8eea84f46f946d92c1b84cf2bd4ceabc57c5c195 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Wed, 6 Apr 2022 09:53:35 -0700 Subject: [PATCH 102/164] Change Curve labeling Curves are now labeled by number rather than name to make the plot look less busy. --- src/Viz/VizProject.jl | 45 ++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index 61a915a5..751e9e51 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -91,8 +91,12 @@ function plotProject!(proj::Project, plotOptions::Int = 0) # Plot the outer innerBoundaries # if !isempty(proj.outerBndryNames) - plotNames = ["Outer."*s for s in proj.outerBndryNames] - plotChain!(plt,proj.outerBndryPoints, plotNames) + plotNumbers = ["O."*string(i) for i in 1:length(proj.outerBndryNames)] + plotNames = String[] + for j = 1:length(proj.outerBndryNames) + push!(plotNames, plotNumbers[j]*"| Outer."*proj.outerBndryNames[j] ) + end + plotChain!(plt,proj.outerBndryPoints, plotNames, plotNumbers) end # # Plot the inner innerBoundaries @@ -101,7 +105,12 @@ function plotProject!(proj::Project, plotOptions::Int = 0) for i = 1:length(proj.innerBoundaryChainNames) innerBndryPts = proj.innerBoundaryPoints[i] innerBndryNames = [ proj.innerBoundaryChainNames[i]*"."*s for s in proj.innerBoundaryNames[i]] - plotChain!(plt,innerBndryPts, innerBndryNames) + plotNumbers = [string(i)*"."*string(j) for j in 1:length(innerBndryNames)] + plotNames = String[] + for j = 1:length(innerBndryNames) + push!(plotNames, plotNumbers[j]*"| "*innerBndryNames[j] ) + end + plotChain!(plt,innerBndryPts, plotNames, plotNumbers) end end if !isempty(proj.outerBndryNames) || !isempty(proj.innerBoundaryChainNames) @@ -153,33 +162,33 @@ function updatePlot!(proj::Project, plotOptions::Int) end end -function plotChain!(plt, chainPoints::Array{Any}, labels::Array{String}) +function plotChain!(plt, chainPoints::Array{Any}, legendLabels::Array{String}, curveLabels::Array{String} ) x = chainPoints[1] - plotCurve(plt, x, labels[1]) + plotCurve(plt, x, legendLabels[1], curveLabels[1]) - s = length(labels) + s = length(legendLabels) for i = 2:s x = chainPoints[i] - plotCurve(plt,x,labels[i]) - end + plotCurve(plt,x,legendLabels[i], curveLabels[i]) + end end -function plotCurve(plt, points::Matrix{Float64}, label::String) - lines!(plt[1,1],points[:,1],points[:,2], label = label, linewidth = 5 ) +function plotCurve(plt, points::Matrix{Float64}, legendLabel::String, curveLabel::String) + lines!(plt[1,1],points[:,1],points[:,2], label = legendLabel, linewidth = 5 ) s = size(points) np = div(s[1], 2, RoundNearest) if s[1] == 3 - np = 2 - end - dx = points[np+1,1] - points[np-1,1] - dy = points[np+1,2] - points[np-1,2] - theta = atan(dy,dx) - if(abs(dy) <= 0.0001) #Not pretty - theta = 0.0 + np = 2 end + # dx = points[np+1,1] - points[np-1,1] + # dy = points[np+1,2] - points[np-1,2] + # theta = atan(dy,dx) + # if(abs(dy) <= 0.0001) #Not pretty + # theta = 0.0 + # end pp = (points[np,1],points[np,2]) - text!(plt[1,1],label,position = pp, align = (:center,:center), rotation = theta ) + text!(plt[1,1],curveLabel,textsize = 28, position = pp, align = (:center,:center) ) end function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String}, loc::Array{Array{Float64}}) From 73f74a84bec4bc7e9f773527133e13d276a9d8de Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 6 Apr 2022 19:39:22 +0200 Subject: [PATCH 103/164] update comment in background tests --- test/test_background_grid.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_background_grid.jl b/test/test_background_grid.jl index 1a18edec..d262ac0b 100644 --- a/test/test_background_grid.jl +++ b/test/test_background_grid.jl @@ -72,8 +72,8 @@ using Test # # There are no longer any background grid. Delete the notification center piece as well. # Note that the notification center is global and can have multiple observers. So we test -# this notification center removal before other observers are created that will add in the -# background grid again. +# this notification center removal before other observers, e.g. other projects in the +# testing runs, are created that will add in the background grid again. # HOHQMesh.unRegisterForNotification(p, "BGRID_DID_CHANGE_NOTIFICATION") @test haskey( HOHQMesh.HQMNotificationCenter , "BGRID_DID_CHANGE_NOTIFICATION" ) == false From 330c95df385cd8247aa99da9fc2c542244e2e485 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 08:31:19 +0200 Subject: [PATCH 104/164] adjust how the project name is set in openProject from a control file name --- src/Mesh/Meshing.jl | 1 - src/Project/Project.jl | 14 +++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 47038b66..9d62732c 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -33,7 +33,6 @@ function generate_mesh(proj::Project) println("A background grid is needed before meshing. Add one and try again.") return nothing end - path = mkpath(proj.projectDirectory) saveProject(proj) fileName = joinpath(proj.projectDirectory,proj.name)*".control" mesherOutput = generate_mesh(fileName, output_directory = proj.projectDirectory) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index c8c6b468..e23fef01 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -75,16 +75,21 @@ include("./SmootherAPI.jl") Open existing project described in the control File. folder = folder the control file is in - fileNmae = the name of the file + fileName = the name of the file """ function openProject(fileName::String, folder::String) controlFile = joinpath(folder,fileName) - splitName = split(fileName,".") - controlDict = ImportControlFile(controlFile) - s = string(splitName[1]) # This is dumb + # Strip off the file path into a temporary name + tempName = splitdir(fileName) + # Separate the project name from `.control` + splitName = split(tempName[2], ".") + # Pull the correct project name + s = string(splitName[1]) # This is dumb + + # Instantiate an empty project with some defaults proj = newProject(s,folder) # # Overwrite defaults @@ -103,7 +108,6 @@ end Save a project dictionary to the file path specified when the project was created. """ function saveProject(proj::Project) - getfolder = mkpath(proj.projectDirectory) fileName = joinpath(proj.projectDirectory,proj.name)*".control" WriteControlFile(proj.projectDictionary,fileName) end From 94b4c3ed4b11cfafc287d927f68c3ee5a2e53369 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 09:22:09 +0200 Subject: [PATCH 105/164] update authors in the docs --- docs/src/index.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 4afc0d97..9caa35c8 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -49,11 +49,11 @@ while the 3D file `Snake.control` produces this mesh: ## Authors -HOHQMesh.jl was initiated by -[Michael Schlottke-Lakemper](https://www.mi.uni-koeln.de/NumSim/schlottke-lakemper) -(University of Cologne, Germany), who is also the principal developer of HOHQMesh.jl. -The *HOHQMesh* mesh generator itself is developed by -[David A. Kopriva](https://www.math.fsu.edu/~kopriva/). +HOHQMesh.jl is maintained by the +[Trixi authors](https://github.com/trixi-framework/Trixi.jl/blob/main/AUTHORS.md). +Its principal developers are [Andrew Winters](https://liu.se/en/employee/andwi94) +(Linköping University, Sweden) and [David A. Kopriva](https://www.math.fsu.edu/~kopriva/). +The *HOHQMesh* mesh generator itself is developed by David A. Kopriva. ## License and contributing From f63689160b5ec6f2a1c79bbbfa9da6ca79e24849 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 10:32:54 +0200 Subject: [PATCH 106/164] adjust spacing in the cheatsheet --- docs/src/CheatSheet.md | 56 ++++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 1191b34e..69393c40 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -10,55 +10,57 @@ Workflow: ## Project - p = newProject(,) + p = newProject( , ) ## [Plotting](@id cs-plotting) - plotProject!(p,options) - updatePlot!(p,options) + plotProject!( p, options ) + updatePlot!( p, options ) ## Curves - c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* - c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* - c = new(name, xEqn, yEqn, zEqn ) *Parametric equation* - c = new(name, dataFile) *Spline* - c = new(name, nKnots, knotsMatrix) *also Spline* + c = new( name, startLocation [x,y,z],endLocation [x,y,z] ) *Straight Line* + c = new( name,center [x,y,z],radius, startAngle, endAngle ) *Circular Arc* + c = new( name, xEqn, yEqn, zEqn ) *Parametric equation* + c = new( name, dataFile ) *Spline* + c = new( name, nKnots, knotsMatrix ) *also Spline* ## [Manual Refinement](@id cs-manual-refinement) - r = newRefinementCenter(name, center, gridSize, radius ) - r = newRefinementLine(name,type, startPoint, endPoint, gridSize, width ) + r = newRefinementCenter( name, center, gridSize, radius ) + r = newRefinementLine( name, type, startPoint, endPoint, gridSize, width ) ## Adding to a Project - add!(p, c) *Add outer boundary curve* - add!(p, c, ) *add curve to an inner boundary* - add!(p, r) *Add refinement region* + add!( p, c ) *Add outer boundary curve* + add!( p, c, ) *Add curve to an inner boundary* + add!( p, r ) *Add refinement region* - addBackgroundGrid!(p, [top, left, bottom, right], [nX,nY,nZ]) *No outer boundary* - addBackgroundGrid!(p, [dx,dy,dz]) *If an outer boundary is present* + addBackgroundGrid!( p, [top, left, bottom, right], [nX, nY, nZ] ) *No outer boundary* + addBackgroundGrid!( p, [dx, dy, dz] ) *If an outer boundary is present* ## Accessing items - crv = getCurve(p,curveName) *Get a curve in the outer boundary* - crv = getCurve(p,curveName, boundaryName) *Get a curve in an inner boundary* - indx, chain = getChain(p,boundaryName) *Get a complete inner boundary curve* - r = getRefinementRegion(p, name) + crv = getCurve( p, curveName ) *Get a curve in the outer boundary* + crv = getCurve( p, curveName, boundaryName ) *Get a curve in an inner boundary* + indx, chain = getChain( p, boundaryName ) *Get a complete inner boundary curve* + r = getRefinementRegion( p, name) ## Removing from Project - removeOuterboundary!(p) *Entire outer boundary curve* - removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve* - remove!(p, name) *Curve in outer boundary* - remove!(p, name, innerBoundaryName) *Curve in inner boundary* - removeRefinementRegion!(p, name) + removeOuterboundary!( p ) *Entire outer boundary curve* + removeInnerBoundary!( p, innerBoundaryName ) *Entire inner boundary curve* + remove!( p, name ) *Curve in outer boundary* + remove!( p, name, innerBoundaryName ) *Curve in inner boundary* + removeRefinementRegion!( p, name ) ## Editing items -All items have set/get methods to edit them. Most actions have undo() and redo(). To find out what the next undo/redo actions are, use undoActionName() and redoActionName() to print them out. +All items have set/get methods to edit them. Most actions have `undo()` and `redo()`. +To find out what the next undo/redo actions are, use `undoActionName()` and `redoActionName()` +to print them to the screen. ## Meshing - generate_mesh(p) - remove_mesh!(p) + generate_mesh( p ) + remove_mesh!( p ) From 4019f3f54ca3b0f75e84afa59d72ad801048e72a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 10:39:09 +0200 Subject: [PATCH 107/164] spacing in cheat sheet --- docs/src/CheatSheet.md | 53 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 69393c40..7c93d923 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -10,48 +10,49 @@ Workflow: ## Project - p = newProject( , ) + p = newProject( , ) ## [Plotting](@id cs-plotting) - plotProject!( p, options ) - updatePlot!( p, options ) + plotProject!( p, options ) + updatePlot!( p, options ) ## Curves - c = new( name, startLocation [x,y,z],endLocation [x,y,z] ) *Straight Line* - c = new( name,center [x,y,z],radius, startAngle, endAngle ) *Circular Arc* - c = new( name, xEqn, yEqn, zEqn ) *Parametric equation* - c = new( name, dataFile ) *Spline* - c = new( name, nKnots, knotsMatrix ) *also Spline* + c = new( name, startLocation [x,y,z],endLocation [x,y,z] ) *Straight Line* + c = new( name,center [x,y,z],radius, startAngle, endAngle ) *Circular Arc* + c = new( name, xEqn, yEqn, zEqn ) *Parametric equation* + c = new( name, dataFile ) *Spline with data from a file* + c = new( name, nKnots, knotsMatrix ) *Spline with given knot values* ## [Manual Refinement](@id cs-manual-refinement) - r = newRefinementCenter( name, center, gridSize, radius ) - r = newRefinementLine( name, type, startPoint, endPoint, gridSize, width ) + r = newRefinementCenter( name, center, gridSize, radius ) + r = newRefinementLine( name, type, startPoint, endPoint, gridSize, width ) + ## Adding to a Project - add!( p, c ) *Add outer boundary curve* - add!( p, c, ) *Add curve to an inner boundary* - add!( p, r ) *Add refinement region* + add!( p, c ) *Add outer boundary curve* + add!( p, c, ) *Add curve to an inner boundary* + add!( p, r ) *Add refinement region* - addBackgroundGrid!( p, [top, left, bottom, right], [nX, nY, nZ] ) *No outer boundary* - addBackgroundGrid!( p, [dx, dy, dz] ) *If an outer boundary is present* + addBackgroundGrid!( p, [top, left, bottom, right], [nX, nY, nZ] ) *No outer boundary* + addBackgroundGrid!( p, [dx, dy, dz] ) *If an outer boundary is present* ## Accessing items - crv = getCurve( p, curveName ) *Get a curve in the outer boundary* - crv = getCurve( p, curveName, boundaryName ) *Get a curve in an inner boundary* - indx, chain = getChain( p, boundaryName ) *Get a complete inner boundary curve* - r = getRefinementRegion( p, name) + crv = getCurve( p, curveName ) *Get a curve in the outer boundary* + crv = getCurve( p, curveName, boundaryName ) *Get a curve in an inner boundary* + indx, chain = getChain( p, boundaryName ) *Get a complete inner boundary curve* + r = getRefinementRegion( p, name) ## Removing from Project - removeOuterboundary!( p ) *Entire outer boundary curve* - removeInnerBoundary!( p, innerBoundaryName ) *Entire inner boundary curve* - remove!( p, name ) *Curve in outer boundary* - remove!( p, name, innerBoundaryName ) *Curve in inner boundary* - removeRefinementRegion!( p, name ) + removeOuterboundary!( p ) *Entire outer boundary curve* + removeInnerBoundary!( p, innerBoundaryName ) *Entire inner boundary curve* + remove!( p, name ) *Curve in outer boundary* + remove!( p, name, innerBoundaryName ) *Curve in inner boundary* + removeRefinementRegion!( p, name ) ## Editing items @@ -61,6 +62,6 @@ to print them to the screen. ## Meshing - generate_mesh( p ) - remove_mesh!( p ) + generate_mesh( p ) + remove_mesh!( p ) From 903f3f881f4718463f4ba23e27835e373b3c09c7 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 10:46:56 +0200 Subject: [PATCH 108/164] wrap commands in a code environment --- docs/src/CheatSheet.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 7c93d923..67d20185 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -10,49 +10,63 @@ Workflow: ## Project +``` p = newProject( , ) +``` ## [Plotting](@id cs-plotting) +``` plotProject!( p, options ) updatePlot!( p, options ) +``` ## Curves +``` c = new( name, startLocation [x,y,z],endLocation [x,y,z] ) *Straight Line* c = new( name,center [x,y,z],radius, startAngle, endAngle ) *Circular Arc* c = new( name, xEqn, yEqn, zEqn ) *Parametric equation* c = new( name, dataFile ) *Spline with data from a file* c = new( name, nKnots, knotsMatrix ) *Spline with given knot values* +``` ## [Manual Refinement](@id cs-manual-refinement) +``` r = newRefinementCenter( name, center, gridSize, radius ) r = newRefinementLine( name, type, startPoint, endPoint, gridSize, width ) +``` ## Adding to a Project +``` add!( p, c ) *Add outer boundary curve* add!( p, c, ) *Add curve to an inner boundary* add!( p, r ) *Add refinement region* addBackgroundGrid!( p, [top, left, bottom, right], [nX, nY, nZ] ) *No outer boundary* addBackgroundGrid!( p, [dx, dy, dz] ) *If an outer boundary is present* +``` ## Accessing items +``` crv = getCurve( p, curveName ) *Get a curve in the outer boundary* crv = getCurve( p, curveName, boundaryName ) *Get a curve in an inner boundary* indx, chain = getChain( p, boundaryName ) *Get a complete inner boundary curve* r = getRefinementRegion( p, name) +``` ## Removing from Project +``` removeOuterboundary!( p ) *Entire outer boundary curve* removeInnerBoundary!( p, innerBoundaryName ) *Entire inner boundary curve* remove!( p, name ) *Curve in outer boundary* remove!( p, name, innerBoundaryName ) *Curve in inner boundary* removeRefinementRegion!( p, name ) +``` ## Editing items @@ -62,6 +76,7 @@ to print them to the screen. ## Meshing +``` generate_mesh( p ) remove_mesh!( p ) - +``` From ac8b27c1996eb28d3a273c3f418859752d6d0f09 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 11:57:03 +0200 Subject: [PATCH 109/164] remove any tabs from CheatSheet spacing --- docs/src/CheatSheet.md | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 67d20185..7f4e9cad 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -11,61 +11,61 @@ Workflow: ## Project ``` - p = newProject( , ) + p = newProject(, ) ``` ## [Plotting](@id cs-plotting) ``` - plotProject!( p, options ) - updatePlot!( p, options ) + plotProject!(p, options) + updatePlot!(p, options) ``` ## Curves ``` - c = new( name, startLocation [x,y,z],endLocation [x,y,z] ) *Straight Line* - c = new( name,center [x,y,z],radius, startAngle, endAngle ) *Circular Arc* - c = new( name, xEqn, yEqn, zEqn ) *Parametric equation* - c = new( name, dataFile ) *Spline with data from a file* - c = new( name, nKnots, knotsMatrix ) *Spline with given knot values* + c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* + c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* + c = new(name, xEqn, yEqn, zEqn) *Parametric equation* + c = new(name, dataFile) *Spline with data from a file* + c = new(name, nKnots, knotsMatrix) *Spline with given knot values* ``` ## [Manual Refinement](@id cs-manual-refinement) ``` - r = newRefinementCenter( name, center, gridSize, radius ) - r = newRefinementLine( name, type, startPoint, endPoint, gridSize, width ) + r = newRefinementCenter(name, center, gridSize, radius) + r = newRefinementLine(name, type, startPoint, endPoint, gridSize, width) ``` ## Adding to a Project ``` - add!( p, c ) *Add outer boundary curve* - add!( p, c, ) *Add curve to an inner boundary* - add!( p, r ) *Add refinement region* + add!(p, c) *Add outer boundary curve* + add!(p, c, ) *Add curve to an inner boundary* + add!(p, r) *Add refinement region* - addBackgroundGrid!( p, [top, left, bottom, right], [nX, nY, nZ] ) *No outer boundary* - addBackgroundGrid!( p, [dx, dy, dz] ) *If an outer boundary is present* + addBackgroundGrid!(p, [top, left, bottom, right], [nX, nY, nZ]) *No outer boundary* + addBackgroundGrid!(p, [dx, dy, dz]) *If an outer boundary is present* ``` ## Accessing items ``` - crv = getCurve( p, curveName ) *Get a curve in the outer boundary* - crv = getCurve( p, curveName, boundaryName ) *Get a curve in an inner boundary* - indx, chain = getChain( p, boundaryName ) *Get a complete inner boundary curve* - r = getRefinementRegion( p, name) + crv = getCurve(p, curveName) *Get a curve in the outer boundary* + crv = getCurve(p, curveName, boundaryName) *Get a curve in an inner boundary* + indx, chain = getChain(p, boundaryName) *Get a complete inner boundary curve* + r = getRefinementRegion(p, name) ``` ## Removing from Project ``` - removeOuterboundary!( p ) *Entire outer boundary curve* - removeInnerBoundary!( p, innerBoundaryName ) *Entire inner boundary curve* - remove!( p, name ) *Curve in outer boundary* - remove!( p, name, innerBoundaryName ) *Curve in inner boundary* - removeRefinementRegion!( p, name ) + removeOuterboundary!(p) *Entire outer boundary curve* + removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve* + remove!(p, name) *Curve in outer boundary* + remove!(p, name, innerBoundaryName) *Curve in inner boundary* + removeRefinementRegion!(p, name) ``` ## Editing items @@ -77,6 +77,6 @@ to print them to the screen. ## Meshing ``` - generate_mesh( p ) - remove_mesh!( p ) + generate_mesh(p) + remove_mesh!(p) ``` From 5c907988e44a69a03d3162e613235452b147b766 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 13:47:07 +0200 Subject: [PATCH 110/164] remove tabs, adjust spacing, introduce code environments, and adjust line breaks of HQMTool docs --- docs/src/HQMTool.md | 652 ++++++++++++++++++++++++++------------------ 1 file changed, 380 insertions(+), 272 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 56d9e3ab..50c600f3 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -27,14 +27,14 @@ HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. HQMTool is an API to build quad/hex meshes. Three examples are included to get you started. The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run - - run_demo("out") - +``` + run_demo("out") +``` where `out` specifies the folder where the resulting mesh and TecPlot files will be saved. The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The "verbose" version of the script is given below. - +```julia function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, @@ -80,27 +80,40 @@ boundary in the shape of an ice cream cone. The "verbose" version of the script return p end +``` +The first line creates a new project, where the mesh and plot file names will be derived +from the project name, "IceCreamCone" written to the specified folder. -The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. - -To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, if desired. As in HOHQMesh, there are four curve classes currently operational: +To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, +if desired. As in HOHQMesh, there are four curve classes currently operational: - Parametric equations - Splines - Lines defined by their end points - Circular arcs -In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with `addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, but they must be added in order, counter-clockwise. - -Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half circular arc. Again, add them in order, counter-clockwise. +In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] +with radius 4, starting at zero and ending at 360 degrees. It is added to the project with +`addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, +but they must be added in order, counter-clockwise. -For convenience, `newProject` will generate default run parameters, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). +Similarly, you create curves and add them to as many inner boundaries that you want to have. +In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half +circular arc. Again, add them in order, counter-clockwise. -One run parameter that must be set manually is the background grid. Since there is an outer boundary, that determines the extent of the domain to be meshed, so only the mesh size needs to be specified using +For convenience, `newProject` will generate default run parameters, like the plot file format +and the smoother. The parameters can be edited with setter commands. For example, the script +sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). - addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) +One run parameter that must be set manually is the background grid. Since there is an outer +boundary, that determines the extent of the domain to be meshed, so only the mesh size needs +to be specified using +``` + addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) +``` -The example sets the background mesh size to be 0.1 in the x and y directions. The z component is ignored. +The example sets the background mesh size to be 0.1 in the x and y directions. +The z component is ignored. The script finishes by generating the quad mesh and plotting the results, as shown below @@ -109,13 +122,14 @@ The script finishes by generating the quad mesh and plotting the results, as sho It also returns the project so that it can be edited further, if desired. To save a control file for HOHQMesh, simply invoke +``` + saveProject(proj::Project, outFile::String) +``` +where outFile is the name of the control file (traditionally with a .control extension). +`saveProject` is automatically called when a mesh is generated. - saveProject(proj::Project,outFile::String) - -where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. - -The third example `ice_cream_cone_demo` is identical to that which was explained above except that the function calls -use the generic version of, e.g., `new` or `add!`. +The third example `ice_cream_cone_demo` is identical to that which was explained above +except that the function calls use the generic version of, e.g., `new` or `add!`. Methods are available to edit a model. For example to move the center of the outer boundary. @@ -124,49 +138,72 @@ Methods are available to edit a model. For example to move the center of the out To create generate a mesh you - [Create a project](#newProject) - - p = newProject(,) + ``` + p = newProject(,) + ``` - [Create inner and outer boundary curves](#DefiningCurves) - - c = new(, startLocation [x,y,z],endLocation [x,y,z]) (Straight Line) - c = new(,center [x,y,z],radius,startAngle,endAngle,units = "degrees" or "radians") (Circular Arc) - c = new(, xEqn, yEqn, zEqn ) (Parametric equation) - c = new(, dataFile) (Spline) - c = new(, nKnots, knotsMatrix) (also Spline) + ``` + c = new(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* + c = new(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* + c = new(, xEqn, yEqn, zEqn) *Parametric equation* + c = new(, dataFile) *Spline with data from a file* + c = new(, nKnots, knotsMatrix) *Spline with given knot values* + ``` - [Add curves](#AddingCurves) to build the model to see what you have added, - - add!(p, ) (Add outer boundary curve) - add!(p, , ) (add curve to an inner boundary) + ``` + add!(p, ) *Add outer boundary curve* + add!(p, , ) *Add curve to an inner boundary* + ``` - To [visualize](#Plotting) the project's model, - - plotProject!(p,MODEL) - - To update the plot at any time, use - - updatePlot!(p, options) - - Options are MODEL, GRID, MESH, and REFINEMENTS. To plot combinations, sum the options, e.g. MODEL+GRID or MODEL+MESH. (You normally are not intersted in the background grid once the mesh is generated.) + ``` + plotProject!(p, MODEL) + ``` + To update the plot at any time, use + ``` + updatePlot!(p, options) + ``` + + Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. + `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not intersted in the background grid once + the mesh is generated.) - Set the [background grid](#(#BackgroundGrid)) - addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) (No outer boundary) - *OR* - addBackgroundGrid!(p, [top, left, bottom, right], num Intervals [nX,nY,nZ]) (No outer boundary) - - addBackgroundGrid!(p, grid size [dx,dy,dz]) (If an outer boundary is present) - -- [Adjust parameters](#RunParameters), if desired (e.g.) - - setPolynomialOrder!(p,order) + When no outer boundary curve is present the background grid can be set with + ``` + addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) + ``` + Or + ``` + addBackgroundGrid!(p, [top value, left value, bottom value, right value], num Intervals [nX,nY,nZ]) + ``` + The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by + `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent + [top value, left value, bottom value, right value] and the number of elements in each direction. + + When an outer boundary is present the background grid can be set as + ``` + addBackgroundGrid!(p, grid size [dx,dy,dz]) + ``` + where the spacing controls the number of elements in each direction. + +- [Adjust parameters](#RunParameters), if desired + ``` + setPolynomialOrder!(p,order) + ``` - Generate the mesh - - generateMesh(p) - -The mesh will be stored in `` with the name `.mesh`. The control file will also be saved in that folder with the name `.control`, which you can read in again later and modify, remesh, etc. The function will print grid information, and will plot the grid as in the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` command. + ``` + generateMesh(p) + ``` + The mesh will be stored in `` with the name `.mesh`. The control file will also be + saved in that folder with the name `.control`, which you can read in again later and modify, + remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in + the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` + command. ## HQMTool API @@ -175,32 +212,45 @@ The mesh will be stored in `` with the name `.mesh`. The co #### New Project - (Return:Project) proj = newProject(name::String, folder::String) - -The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to add is the [background grid](#BackgroundGrid). +``` + [Return:Project] proj = newProject(name::String, folder::String) +``` +The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is +the directory in which those files will be placed. The empty project will include default `RunParameters` +and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to +add is the [background grid](#BackgroundGrid). #### Opening an existing project file - (Return:Project) proj = openProject(fileName::String, folder::String) +A project can be created from an existing HOHQMesh control file with +``` + [Return:Project] proj = openProject(fileName::String, folder::String) +``` +The supplied `fileName` will be the name of the project and the generated mesh and plot files will be placed +in the supplied `folder`. #### Saving a project - - saveProject(proj::Project) - -writes a control file to the folder designated when creating the new project. It can be read in again with OpenProject. +``` + saveProject(proj::Project) +``` +writes a control file to the folder designated when creating the new project. +It can be read in again with `openProject`. ### Plotting #### Plotting a Project - - plotProject!(proj::Project, options) - -The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show where [manual refinement](#ManualRefinement) is added. +``` + plotProject!(proj::Project, options) +``` +The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, +which you an view to make sure that it can resolve the boundary curves in the model. +Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show +where [manual refinement](#ManualRefinement) is added. If the model is modified and you want to re-plot with the new values, invoke - - updatePlot!(proj::Project, options) - +``` + updatePlot!(proj::Project, options) +``` but genrally the plot will be updated automatically as you build the model. @@ -209,121 +259,142 @@ but genrally the plot will be updated automatically as you build the model. #### Setting the name of a project The project name is the name under which the mesh, plot, statistics and control files will be written. - - setName!(proj::Project,name::String) - +``` + setName!(proj::Project,name::String) +``` #### Getting the current name of a Project - - [Return:String] getName(proj::Project) +``` + [Return:String] getName(proj::Project) +``` ### Controlling the Mesh Generation Process #### Editing the Run Parameters The run parameters can be enquired and set with these getter/setter pairs: - - [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) - [Return:Int] getPolynomialOrder(proj::Project) - [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) - [Return:String] getMeshFileFormat(proj::Project) - [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) - [Return:String] getPlotFileFormat(proj::Project) - -The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. +``` + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) + [Return:Int] getPolynomialOrder(proj::Project) + [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) + [Return:String] getMeshFileFormat(proj::Project) + [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) + [Return:String] getPlotFileFormat(proj::Project) +``` + +The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something +like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element +represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. #### Changing the output file names -By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with - - [Return:nothing] setName!(proj::Project,name::String) - [Return:String] getName(proj::Project) - [Return:nothing] setFolder!(proj::Project,folder::String) - [Return:String] getFolder(proj::Project) +By default, the mesh, plot and stats files will be written with the name and path supplied when +newProject is called. They can be changed/enquired with +``` + [Return:nothing] setName!(proj::Project,name::String) + [Return:String] getName(proj::Project) + [Return:nothing] setFolder!(proj::Project,folder::String) + [Return:String] getFolder(proj::Project) +``` #### Adding the background grid -There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. - - [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) - -Use one of the first two if there is no outer boundary. With the first, a rectangular outer boundary will be created of extent [x0[1], x0[1]+N dx[1]]X[x0[2], x0[2]+N*dx[2]]. The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. The arrays `x0`, `dx`, `N`, `bgSize` are all vectors [ *, \*, \*] giving the x, y, and z components. +There are three forms for the background grid definition, one for when there is an outer boundary, +and two for when there is not. One or the other has to be specified after a new project has been created. +``` + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) +``` +Use one of the first two if there is no outer boundary present in the model. With the first, a rectangular +outer boundary will be created of extent `[x0[1], x0[1] + N*dx[1]]` by `[x0[2], x0[2] + N*dx[2]]`. +The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. +The arrays `x0`, `dx`, `N`, `bgSize` are all vectors `[ *, *, * ]` giving the x, y, and z components. #### Smoothing Operations -A default smoother is created when newProject is called, which sets the status to `ON`, type to `LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. The most likely parameter to change is the number of iterations. +A default smoother is created when `newProject` is called, which sets the status to `ON`, type to +`LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. +The most likely parameter to change is the number of iterations. To change the defaults, the smoother parameters can be set/enquired with the functions - - [Return:nothing] setSmoothingStatus!(proj::Project, status::String) - [Return:String] getSmoothingStatus(proj::Project) - [Return:nothing] setSmoothingType!(proj::Project, type::String) - [Return:String] getSmoothingType(proj::Project) - [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) - [Return:Int] getSmoothingIterations(proj::Project) - -`status` is either "ON" or "OFF". +``` + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) + [Return:String] getSmoothingStatus(proj::Project) + [Return:nothing] setSmoothingType!(proj::Project, type::String) + [Return:String] getSmoothingType(proj::Project) + [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) + [Return:Int] getSmoothingIterations(proj::Project) +``` +The smooth `status` is either "ON" or "OFF". To remove the smoother altogether, - - [Return:nothing] removeSpringSmoother!(proj::Project) +``` + [Return:nothing] removeSpringSmoother!(proj::Project) +``` #### Manual Refinement -Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. +Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, +using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of +the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. To create a refinement center, - - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, type::String, - x0::Array{Float64}, h::Float64, - w::Float64 ) - -where the type is either `smooth` or `sharp`, `x0` = [x,y,z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. +``` + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, + type::String, + x0::Array{Float64}, + h::Float64, + w::Float64) +``` +where the type is either `smooth` or `sharp`, `x0` = [x, y, z] is the location of the center, `h` is the mesh size, +and `w` is the extent of the refinement region. Similarly, one can create a `RefinementLine`, - - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, - x0::Array{Float64}, x1::Array{Float64}, - h::Float64, - w::Float64 ) - +``` + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64) +``` where `x0` is the start postition and `x1` is the end of the line. To add a refinement region to the project, +``` + [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) +``` - [Return:nothing] addRefinementRegion!(proj::Project,r::Dict{String,Any}) - -To get the indx'th refinement region from the project, or to get - a refinement region with a given name, use - - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) +To get the indx'th refinement region from the project, or to get a refinement region with a given name, use +``` + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) +``` Finally, to get a list of all the refinement regions, - - [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) +``` + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) +``` A refinement region can be edited by using the following - - [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) - [Return:String] getRefinementType(r::Dict{String,Any}) - [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) - [Return:nothing] setRefinementGridSize!(r::Dict{String,Any},h::Float64) - [Return:float64] getRefinementGridSize(r::Dict{String,Any}) - [Return:nothing] setRefinementWidth!(r::Dict{String,Any},w::Float64) - [Return:float64] getRefinementWidth(r::Dict{String,Any}) - +``` + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) + [Return:String] getRefinementType(r::Dict{String,Any}) + [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) + [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) + [Return:float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) + [Return:float64] getRefinementWidth(r::Dict{String,Any}) +``` where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. To further edit a `RefinementLine`, use the methods - - [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) - [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) +``` + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) + [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) +``` ### Boundary Curves @@ -331,182 +402,219 @@ To further edit a `RefinementLine`, use the methods - Adding an outer boundary curve - Using the curve creation routines, described in the next section below, create curves in sucessive order counter-clockwise along the outer boundary and add them to the outer boundary curve using + Using the curve creation routines, described in the next section below, create curves in sucessive + order counter-clockwise along the outer boundary and add them to the outer boundary curve using + ``` + [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + Generic: add!(...) + ``` + `crv` is the dictionary that represents the curve. - [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - Generic: add!(...) - - `crv` is the dictionary that represents the curve. - -Example: - - add!(p,circ) + Example: + ```julia + circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + add!(p, circ) + ``` - Adding an inner boundary curve - [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - Generic: add!(...) - -Example: - - add!(p,cone1,"IceCreamCone") - -To edit curves they can be accessed by name: - - [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - Generic: getCurve(...) - [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) - Generic: getCurve(...) + The syntax is analogous to the creation of an outer boundary curve where, again, curve creation must + be ordered counter-clockwise. + ``` + [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + Generic: add!(...) + ``` + + Example: + ```julia + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + add!(p, cone1, "IceCreamCone") + ``` + + To edit curves they can be accessed by name: + ``` + [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + Generic: getCurve(...) + [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) + Generic: getCurve(...) + ``` - Deleting boundary curves - [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) - Generic: remove!(...) - [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - Generic: remove!(...) + The entire outer boundary or an entire inner boundary can be removed from the project. + ``` + [Return:nothing] removeOuterBoundary!(proj::Project) + [Return:nothing] removeInnerBoundary!(proj::Project, chainName::String) + ``` + Alternatively, individual pieces of the boundary curve chains can be removed. + ``` + [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) + Generic: remove!(...) + [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + Generic: remove!(...) + ``` + As in HOHQMesh the project can have only one outer boundary chain, so the removal does not + require a specific `chainName`. #### Defining Curves Four curve types can be added to the outer and inner boundary curve chains. They are -- parametricEquation -- endPointsLine -- circularArc -- spline - +- Parametric equations +- Splines +- Lines defined by their end points +- Circular arcs ##### Parametric Equations -- Creating new +Creating a new curve equation +``` + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0") + Generic: new(...) +``` +Returns a new set of parametric equation. Equations must be of the form +``` + () = ... +``` +The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. +The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted +as floating point numbers. - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) - Generic: new(...) - - Returns a new parametric equation. Equations must be of the form - - () = ... - - The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted as floating point numbers. - - Example: +Example: +``` + x(s) = 2.0 + 3*cos(2*pi*s)^2 +``` +The z-Equation is optional, but for now must define zero for z by default. - x(s) = 2.0 + 3*cos(2*pi*s)^2 +##### Spline Curve - The z-Equation is optional, but for now must define zero for z. +A spline is defined by an array of knots, tj,xj,yj,zj. +It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define +the t,x,y,z values, e.g. +``` + 9 + 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 + 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 + 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 + 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 + 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 + 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 + 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 + 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 + 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 +``` +or by constructing the `nKnots` by `4` array supplying it to the new procedure. The respective constructors are +``` + [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) + Generic: new(...) + [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) + Generic: new(...) +``` +If the spline curve is to be closed. The last data point must be the same as the first. ##### Line Defined by End Points - [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - Generic: new(...) - -The `xStart` and `xEnd` are arrays of the form [x,y,z]. The `z` component should be zero and for now is ignored. +A straight line is constructed with +``` + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) + Generic: new(...) +``` +The `xStart` and `xEnd` are arrays of the form [x, y, z]. The `z` component should be zero and for now is ignored. Example: +``` + cone1 = new("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) +``` - cone1 = new("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) ##### Circular Arc - - [Return:Dict{String,Any}] newCircularArcCurve(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String) - Generic: new(...) - - The center is an array of the form [x,y,z]. The units argument defines the start and end angle units, and is either "degrees" or "radians". That argument is optional, and defaults to "degrees". +``` + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) + Generic: new(...) +``` +The center is an array of the form [x, y, z]. The units argument defines the start and end angle units. +It is either "degrees" or "radians". That argument is optional, and defaults to "degrees". Example: - - iceCream = new("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") - -##### Spline Curve - -A spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. - - 9 - 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 - 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 - 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 - 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 - 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 - 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 - 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 - 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 - 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 - -or by constructing the Nx4 array supplying it to the new procedure. The constructors are - - [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) - Generic: new(...) - [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) - Generic: new(...) - -If the curve is to be closed. The last point must be the same as the first. +``` + iceCream = new("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") +``` #### Editing Curves You can determine the type of a curve by - - [Return:String] getCurveType(crv::Dict{String,Any}) +``` + [Return:String] getCurveType(crv::Dict{String,Any}) +``` For any of the curves, their name can be changed by - - setCurveName!(crv::Dict{String,Any}, name::String) - +``` + setCurveName!(crv::Dict{String,Any}, name::String) +``` and checked by - - getCurveName(crv::Dict{String,Any}) +``` + getCurveName(crv::Dict{String,Any}) +``` Otherwise there are special functions to change the parameters of curves - - [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) - [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) - - [Return:String] getXEqn(crv::Dict{String,Any}) - [Return:String] getYEqn(crv::Dict{String,Any}) - [Return:String] getZEqn(crv::Dict{String,Any}) - [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) - [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) - [Return:String] getArcUnits(arc::Dict{String,Any}) - [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) - [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) - [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) - [Return:Float64] getArcRadius(arc::Dict{String,Any}) +``` + [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) + [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + [Return:String] getXEqn(crv::Dict{String,Any}) + [Return:String] getYEqn(crv::Dict{String,Any}) + [Return:String] getZEqn(crv::Dict{String,Any}) + [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) + [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) + [Return:String] getArcUnits(arc::Dict{String,Any}) + [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) + [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) + [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) + [Return:Float64] getArcRadius(arc::Dict{String,Any}) +``` ### Undo/Redo The HQMTool has unlimited undo/redo for most actions. In interactive mode, actions can be undone by the commands - - [Return:String] undo() - [Return:String] redo() - +``` + [Return:String] undo() + [Return:String] redo() +``` where the return string contains the name of the action performed. To find out what the next actions are, use - - [Return:String] undoName() - [Return:String] redoName() +``` + [Return:String] undoActionName() + [Return:String] redoActionName() +``` Finally, to clear the undo stack, use - - [Return:nothing] clearUndoRedo() +``` + [Return:nothing] clearUndoRedo() +``` ## Advanced -All curves are actually dictionaries of type `Dict{String,Any}`, and since Julia is not a particularly object oriented language, the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, are of type `Dict{String,Any}`. The project holds all the control and model objects in its `projectDirectory`. However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file +All curves are actually dictionaries of type `Dict{String, Any}`, and since Julia is not a particularly object oriented language, +the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, +are of type `Dict{String, Any}`. The project holds all the control and model objects in its `projectDirectory`. +However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file From bf04082dc9eef632243a90f7d3eb811881582bf4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 13:56:29 +0200 Subject: [PATCH 111/164] add cleanup of preview docs --- .github/workflows/DocPreviewCleanup.yml | 32 +++++++++++++++++++++++++ docs/src/index.md | 13 ++++++++++ 2 files changed, 45 insertions(+) create mode 100644 .github/workflows/DocPreviewCleanup.yml diff --git a/.github/workflows/DocPreviewCleanup.yml b/.github/workflows/DocPreviewCleanup.yml new file mode 100644 index 00000000..a8f05276 --- /dev/null +++ b/.github/workflows/DocPreviewCleanup.yml @@ -0,0 +1,32 @@ +name: Doc Preview Cleanup + +on: + pull_request: + types: [closed] + +jobs: + doc-preview-cleanup: + # Do not run on forks to avoid authorization errors + # Source: https://github.community/t/have-github-action-only-run-on-master-repo-and-not-on-forks/140840/18 + if: github.repository_owner == 'trixi-framework' + runs-on: ubuntu-latest + steps: + - name: Checkout gh-pages branch + uses: actions/checkout@v2 + with: + ref: gh-pages + + - name: Delete preview and history + shell: bash + run: | + git config user.name "Documenter.jl" + git config user.email "documenter@juliadocs.github.io" + git rm -rf --ignore-unmatch "previews/PR$PRNUM" + git commit -m "delete preview" --allow-empty + git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree}) + env: + PRNUM: ${{ github.event.number }} + + - name: Push changes + run: | + git push --force origin gh-pages-new:gh-pages diff --git a/docs/src/index.md b/docs/src/index.md index 9caa35c8..992defcd 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -60,6 +60,19 @@ The *HOHQMesh* mesh generator itself is developed by David A. Kopriva. HOHQMesh.jl is licensed under the MIT license (see [License](@ref)). *HOHQMesh* itself is also available under the MIT license. +### Preview of the documentation + +You can build the documentation of HOHQMesh.jl locally by running +```bash +julia --project=docs -e 'using Pkg; Pkg.instantiate(); include("docs/make.jl")' +``` +from the HOHQMesh.jl main directory. Then, you can look at the html files generated in +`docs/build`. +For PRs triggered from branches inside the HOHQMesh.jl main repository previews of +the new documentation are generated at `https://trixi-framework.github.io/HOHQMesh.jl/previews/PRXXX`, +where `XXX` is the number of the PR. +Note, this does not work for PRs from forks for security reasons (since anyone could otherwise push +arbitrary stuff, including malicious code). ## Acknowledgements The authors would like to thank David A. Kopriva for making the sources of From 28d169924066e912fdb2ef8f7a6b6d3b1a89a18d Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 14:45:08 +0200 Subject: [PATCH 112/164] switch to three spaces for indent. Renders better with githubs markdown --- docs/src/CheatSheet.md | 52 ++-- docs/src/HQMTool.md | 592 +++++++++++++++++++++-------------------- 2 files changed, 334 insertions(+), 310 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index 7f4e9cad..b0fbea20 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -11,61 +11,61 @@ Workflow: ## Project ``` - p = newProject(, ) + p = newProject(, ) ``` ## [Plotting](@id cs-plotting) ``` - plotProject!(p, options) - updatePlot!(p, options) + plotProject!(p, options) + updatePlot!(p, options) ``` ## Curves ``` - c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* - c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* - c = new(name, xEqn, yEqn, zEqn) *Parametric equation* - c = new(name, dataFile) *Spline with data from a file* - c = new(name, nKnots, knotsMatrix) *Spline with given knot values* + c = new(name, startLocation [x,y,z],endLocation [x,y,z]) *Straight Line* + c = new(name,center [x,y,z],radius, startAngle, endAngle) *Circular Arc* + c = new(name, xEqn, yEqn, zEqn) *Parametric equation* + c = new(name, dataFile) *Spline with data from a file* + c = new(name, nKnots, knotsMatrix) *Spline with given knot values* ``` ## [Manual Refinement](@id cs-manual-refinement) ``` - r = newRefinementCenter(name, center, gridSize, radius) - r = newRefinementLine(name, type, startPoint, endPoint, gridSize, width) + r = newRefinementCenter(name, center, gridSize, radius) + r = newRefinementLine(name, type, startPoint, endPoint, gridSize, width) ``` ## Adding to a Project ``` - add!(p, c) *Add outer boundary curve* - add!(p, c, ) *Add curve to an inner boundary* - add!(p, r) *Add refinement region* + add!(p, c) *Add outer boundary curve* + add!(p, c, ) *Add curve to an inner boundary* + add!(p, r) *Add refinement region* - addBackgroundGrid!(p, [top, left, bottom, right], [nX, nY, nZ]) *No outer boundary* - addBackgroundGrid!(p, [dx, dy, dz]) *If an outer boundary is present* + addBackgroundGrid!(p, [top, left, bottom, right], [nX, nY, nZ]) *No outer boundary* + addBackgroundGrid!(p, [dx, dy, dz]) *If an outer boundary is present* ``` ## Accessing items ``` - crv = getCurve(p, curveName) *Get a curve in the outer boundary* - crv = getCurve(p, curveName, boundaryName) *Get a curve in an inner boundary* - indx, chain = getChain(p, boundaryName) *Get a complete inner boundary curve* - r = getRefinementRegion(p, name) + crv = getCurve(p, curveName) *Get a curve in the outer boundary* + crv = getCurve(p, curveName, boundaryName) *Get a curve in an inner boundary* + indx, chain = getChain(p, boundaryName) *Get a complete inner boundary curve* + r = getRefinementRegion(p, name) ``` ## Removing from Project ``` - removeOuterboundary!(p) *Entire outer boundary curve* - removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve* - remove!(p, name) *Curve in outer boundary* - remove!(p, name, innerBoundaryName) *Curve in inner boundary* - removeRefinementRegion!(p, name) + removeOuterboundary!(p) *Entire outer boundary curve* + removeInnerBoundary!(p, innerBoundaryName) *Entire inner boundary curve* + remove!(p, name) *Curve in outer boundary* + remove!(p, name, innerBoundaryName) *Curve in inner boundary* + removeRefinementRegion!(p, name) ``` ## Editing items @@ -77,6 +77,6 @@ to print them to the screen. ## Meshing ``` - generate_mesh(p) - remove_mesh!(p) + generate_mesh(p) + remove_mesh!(p) ``` diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 50c600f3..278977ac 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -28,58 +28,58 @@ HQMTool is an API to build quad/hex meshes. Three examples are included to get y The first reads in an existing control file from the HOHQMesh examples collection. To see that example, run ``` - run_demo("out") + run_demo("out") ``` where `out` specifies the folder where the resulting mesh and TecPlot files will be saved. The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The "verbose" version of the script is given below. ```julia - function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) - # - # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `folder`. The keyword arguement `called_by_user` is there for testing purposes. - # - p = newProject("IceCreamCone", folder) - # - # Outer boundary - # - circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") - addCurveToOuterBoundary!(p, circ) - # - # Inner boundary - # - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p, cone1, "IceCreamCone") - addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") - addCurveToInnerBoundary!(p, cone2, "IceCreamCone") - # - # Set some control RunParameters to overwrite the defaults - # - setPolynomialOrder!(p, 4) - setPlotFileFormat!(p, "sem") - # - # To mesh, a background grid is needed - # - addBackgroundGrid!(p, [0.5,0.5,0.0]) - - if called_by_user - # - # Show the model and grid - # - plotProject!(p, MODEL+GRID) - println("Press enter to continue and generate the mesh") - readline() - end - # - # Generate the mesh and plot - # - generate_mesh(p) - - return p - end + function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) + # + # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, + # written to `folder`. The keyword arguement `called_by_user` is there for testing purposes. + # + p = newProject("IceCreamCone", folder) + # + # Outer boundary + # + circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + addCurveToOuterBoundary!(p, circ) + # + # Inner boundary + # + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") + cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) + addCurveToInnerBoundary!(p, cone1, "IceCreamCone") + addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") + addCurveToInnerBoundary!(p, cone2, "IceCreamCone") + # + # Set some control RunParameters to overwrite the defaults + # + setPolynomialOrder!(p, 4) + setPlotFileFormat!(p, "sem") + # + # To mesh, a background grid is needed + # + addBackgroundGrid!(p, [0.5,0.5,0.0]) + + if called_by_user + # + # Show the model and grid + # + plotProject!(p, MODEL+GRID) + println("Press enter to continue and generate the mesh") + readline() + end + # + # Generate the mesh and plot + # + generate_mesh(p) + + return p + end ``` The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. @@ -109,7 +109,7 @@ One run parameter that must be set manually is the background grid. Since there boundary, that determines the extent of the domain to be meshed, so only the mesh size needs to be specified using ``` - addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) ``` The example sets the background mesh size to be 0.1 in the x and y directions. @@ -117,13 +117,13 @@ The z component is ignored. The script finishes by generating the quad mesh and plotting the results, as shown below -![iceCreamCone](https://user-images.githubusercontent.com/3637659/132798939-218a3379-7d50-4f3e-9bec-e75e6cd79031.png) +![iceCreamCone](https://user-images.githubusercontent.com/25242486/162193980-b80fb92c-2851-4809-af01-be856152514f.png) It also returns the project so that it can be edited further, if desired. To save a control file for HOHQMesh, simply invoke ``` - saveProject(proj::Project, outFile::String) + saveProject(proj::Project, outFile::String) ``` where outFile is the name of the control file (traditionally with a .control extension). `saveProject` is automatically called when a mesh is generated. @@ -135,75 +135,90 @@ Methods are available to edit a model. For example to move the center of the out ## Basic Moves -To create generate a mesh you - -- [Create a project](#newProject) - ``` - p = newProject(,) - ``` - -- [Create inner and outer boundary curves](#DefiningCurves) - ``` - c = new(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* - c = new(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* - c = new(, xEqn, yEqn, zEqn) *Parametric equation* - c = new(, dataFile) *Spline with data from a file* - c = new(, nKnots, knotsMatrix) *Spline with given knot values* - ``` - -- [Add curves](#AddingCurves) to build the model to see what you have added, - ``` - add!(p, ) *Add outer boundary curve* - add!(p, , ) *Add curve to an inner boundary* - ``` - -- To [visualize](#Plotting) the project's model, - ``` - plotProject!(p, MODEL) - ``` - To update the plot at any time, use - ``` - updatePlot!(p, options) - ``` - - Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. - `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not intersted in the background grid once - the mesh is generated.) - -- Set the [background grid](#(#BackgroundGrid)) - - When no outer boundary curve is present the background grid can be set with - ``` - addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) - ``` - Or - ``` - addBackgroundGrid!(p, [top value, left value, bottom value, right value], num Intervals [nX,nY,nZ]) - ``` - The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by - `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent - [top value, left value, bottom value, right value] and the number of elements in each direction. - - When an outer boundary is present the background grid can be set as - ``` - addBackgroundGrid!(p, grid size [dx,dy,dz]) - ``` - where the spacing controls the number of elements in each direction. - -- [Adjust parameters](#RunParameters), if desired - ``` - setPolynomialOrder!(p,order) - ``` - -- Generate the mesh - ``` - generateMesh(p) - ``` - The mesh will be stored in `` with the name `.mesh`. The control file will also be - saved in that folder with the name `.control`, which you can read in again later and modify, - remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in - the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` - command. +To generate a mesh using HQMTool you + +1. [Create a project](#newProject) + + ``` + p = newProject(,) + ``` + +2. [Create inner and outer boundary curves](#DefiningCurves) + + ``` + c = new(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* + c = new(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* + c = new(, xEqn, yEqn, zEqn) *Parametric equation* + c = new(, dataFile) *Spline with data from a file* + c = new(, nKnots, knotsMatrix) *Spline with given knot values* + ``` + +3. [Add curves](#AddingCurves) to build the model to see what you have added, + + ``` + add!(p, ) *Add outer boundary curve* + add!(p, , ) *Add curve to an inner boundary* + ``` + +4. To [visualize](#Plotting) the project's model, + + ``` + plotProject!(p, MODEL) + ``` + + To update the plot at any time, use + + ``` + updatePlot!(p, options) + ``` + + Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. + `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not intersted in the background grid once + the mesh is generated.) + +5. Set the [background grid](#(#BackgroundGrid)) + + When no outer boundary curve is present the background grid can be set with + + ``` + addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) + ``` + + Or + + ``` + addBackgroundGrid!(p, [top value, left value, bottom value, right value], num Intervals [nX,nY,nZ]) + ``` + + The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by + `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent + [top value, left value, bottom value, right value] and the number of elements in each direction. + + When an outer boundary is present the background grid can be set as + + ``` + addBackgroundGrid!(p, grid size [dx,dy,dz]) + ``` + + where the spacing controls the number of elements in each direction. + +6. [Adjust parameters](#RunParameters), if desired + + ``` + setPolynomialOrder!(p,order) + ``` + +7. Generate the mesh + + ``` + generate_mesh(p) + ``` + +The mesh will be stored in `` with the name `.mesh`. The control file will also be +saved in that folder with the name `.control`, which you can read in again later and modify, +remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in +the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` +command. ## HQMTool API @@ -211,9 +226,8 @@ To create generate a mesh you ### Project Creation and Saving #### New Project - ``` - [Return:Project] proj = newProject(name::String, folder::String) + [Return:Project] proj = newProject(name::String, folder::String) ``` The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is the directory in which those files will be placed. The empty project will include default `RunParameters` @@ -224,14 +238,14 @@ add is the [background grid](#BackgroundGrid). A project can be created from an existing HOHQMesh control file with ``` - [Return:Project] proj = openProject(fileName::String, folder::String) + [Return:Project] proj = openProject(fileName::String, folder::String) ``` The supplied `fileName` will be the name of the project and the generated mesh and plot files will be placed in the supplied `folder`. #### Saving a project ``` - saveProject(proj::Project) + saveProject(proj::Project) ``` writes a control file to the folder designated when creating the new project. It can be read in again with `openProject`. @@ -240,7 +254,7 @@ It can be read in again with `openProject`. #### Plotting a Project ``` - plotProject!(proj::Project, options) + plotProject!(proj::Project, options) ``` The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. @@ -249,7 +263,7 @@ where [manual refinement](#ManualRefinement) is added. If the model is modified and you want to re-plot with the new values, invoke ``` - updatePlot!(proj::Project, options) + updatePlot!(proj::Project, options) ``` but genrally the plot will be updated automatically as you build the model. @@ -260,12 +274,12 @@ but genrally the plot will be updated automatically as you build the model. The project name is the name under which the mesh, plot, statistics and control files will be written. ``` - setName!(proj::Project,name::String) + setName!(proj::Project,name::String) ``` #### Getting the current name of a Project ``` - [Return:String] getName(proj::Project) + [Return:String] getName(proj::Project) ``` ### Controlling the Mesh Generation Process @@ -274,12 +288,12 @@ The project name is the name under which the mesh, plot, statistics and control The run parameters can be enquired and set with these getter/setter pairs: ``` - [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) - [Return:Int] getPolynomialOrder(proj::Project) - [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) - [Return:String] getMeshFileFormat(proj::Project) - [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) - [Return:String] getPlotFileFormat(proj::Project) + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) + [Return:Int] getPolynomialOrder(proj::Project) + [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) + [Return:String] getMeshFileFormat(proj::Project) + [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) + [Return:String] getPlotFileFormat(proj::Project) ``` The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something @@ -291,10 +305,10 @@ represntation of the mesh. The latter (which is a much bigger file) includes the By default, the mesh, plot and stats files will be written with the name and path supplied when newProject is called. They can be changed/enquired with ``` - [Return:nothing] setName!(proj::Project,name::String) - [Return:String] getName(proj::Project) - [Return:nothing] setFolder!(proj::Project,folder::String) - [Return:String] getFolder(proj::Project) + [Return:nothing] setName!(proj::Project,name::String) + [Return:String] getName(proj::Project) + [Return:nothing] setFolder!(proj::Project,folder::String) + [Return:String] getFolder(proj::Project) ``` #### Adding the background grid @@ -302,9 +316,9 @@ newProject is called. They can be changed/enquired with There are three forms for the background grid definition, one for when there is an outer boundary, and two for when there is not. One or the other has to be specified after a new project has been created. ``` - [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) + [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) ``` Use one of the first two if there is no outer boundary present in the model. With the first, a rectangular outer boundary will be created of extent `[x0[1], x0[1] + N*dx[1]]` by `[x0[2], x0[2] + N*dx[2]]`. @@ -319,18 +333,18 @@ The most likely parameter to change is the number of iterations. To change the defaults, the smoother parameters can be set/enquired with the functions ``` - [Return:nothing] setSmoothingStatus!(proj::Project, status::String) - [Return:String] getSmoothingStatus(proj::Project) - [Return:nothing] setSmoothingType!(proj::Project, type::String) - [Return:String] getSmoothingType(proj::Project) - [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) - [Return:Int] getSmoothingIterations(proj::Project) + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) + [Return:String] getSmoothingStatus(proj::Project) + [Return:nothing] setSmoothingType!(proj::Project, type::String) + [Return:String] getSmoothingType(proj::Project) + [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) + [Return:Int] getSmoothingIterations(proj::Project) ``` The smooth `status` is either "ON" or "OFF". To remove the smoother altogether, ``` - [Return:nothing] removeSpringSmoother!(proj::Project) + [Return:nothing] removeSpringSmoother!(proj::Project) ``` #### Manual Refinement @@ -341,33 +355,33 @@ the solution where refinement is needed (e.g. a wake) or in problematic areas in To create a refinement center, ``` - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, - type::String, - x0::Array{Float64}, - h::Float64, - w::Float64) + [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, + type::String, + x0::Array{Float64}, + h::Float64, + w::Float64) ``` where the type is either `smooth` or `sharp`, `x0` = [x, y, z] is the location of the center, `h` is the mesh size, and `w` is the extent of the refinement region. Similarly, one can create a `RefinementLine`, ``` - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, - x0::Array{Float64}, x1::Array{Float64}, - h::Float64, - w::Float64) + [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64) ``` where `x0` is the start postition and `x1` is the end of the line. To add a refinement region to the project, ``` - [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) + [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) ``` To get the indx'th refinement region from the project, or to get a refinement region with a given name, use ``` - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) ``` Finally, to get a list of all the refinement regions, @@ -377,84 +391,94 @@ Finally, to get a list of all the refinement regions, A refinement region can be edited by using the following ``` - [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) - [Return:String] getRefinementType(r::Dict{String,Any}) - [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) - [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) - [Return:float64] getRefinementGridSize(r::Dict{String,Any}) - [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) - [Return:float64] getRefinementWidth(r::Dict{String,Any}) + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) + [Return:String] getRefinementType(r::Dict{String,Any}) + [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) + [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) + [Return:float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) + [Return:float64] getRefinementWidth(r::Dict{String,Any}) ``` where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. To further edit a `RefinementLine`, use the methods ``` - [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) - [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) + [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) ``` ### Boundary Curves #### Adding and Removing Outer and Inner Boundaries -- Adding an outer boundary curve - - Using the curve creation routines, described in the next section below, create curves in sucessive - order counter-clockwise along the outer boundary and add them to the outer boundary curve using - ``` - [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - Generic: add!(...) - ``` - `crv` is the dictionary that represents the curve. - - Example: - ```julia - circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") - add!(p, circ) - ``` - -- Adding an inner boundary curve - - The syntax is analogous to the creation of an outer boundary curve where, again, curve creation must - be ordered counter-clockwise. - ``` - [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - Generic: add!(...) - ``` - - Example: - ```julia - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) - add!(p, cone1, "IceCreamCone") - ``` - - To edit curves they can be accessed by name: - ``` - [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - Generic: getCurve(...) - [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) - Generic: getCurve(...) - ``` - -- Deleting boundary curves - - The entire outer boundary or an entire inner boundary can be removed from the project. - ``` - [Return:nothing] removeOuterBoundary!(proj::Project) - [Return:nothing] removeInnerBoundary!(proj::Project, chainName::String) - ``` - Alternatively, individual pieces of the boundary curve chains can be removed. - ``` - [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) - Generic: remove!(...) - [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - Generic: remove!(...) - ``` - As in HOHQMesh the project can have only one outer boundary chain, so the removal does not - require a specific `chainName`. +1. Adding an outer boundary curve + + Using the curve creation routines, described in the next section below, create curves in sucessive + order counter-clockwise along the outer boundary and add them to the outer boundary curve using + + ``` + [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) + Generic: add!(...) + ``` + + `crv` is the dictionary that represents the curve. + + Example: + + ```julia + circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + add!(p, circ) + ``` + +2. Adding an inner boundary curve + + The syntax is analogous to the creation of an outer boundary curve where, again, curve creation must + be ordered counter-clockwise. + + ``` + [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) + Generic: add!(...) + ``` + + Example: + + ```julia + cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + add!(p, cone1, "IceCreamCone") + ``` + + To edit curves they can be accessed by name: + + ``` + [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) + Generic: getCurve(...) + [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) + Generic: getCurve(...) + ``` + +3. Deleting boundary curves + + The entire outer boundary or an entire inner boundary can be removed from the project. + + ``` + [Return:nothing] removeOuterBoundary!(proj::Project) + [Return:nothing] removeInnerBoundary!(proj::Project, chainName::String) + ``` + + Alternatively, individual pieces of the boundary curve chains can be removed. + + ``` + [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) + Generic: remove!(...) + [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) + Generic: remove!(...) + ``` + + As in HOHQMesh the project can have only one outer boundary chain, so the removal does not + require a specific `chainName`. #### Defining Curves @@ -469,15 +493,15 @@ Four curve types can be added to the outer and inner boundary curve chains. They Creating a new curve equation ``` - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0") - Generic: new(...) + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0") + Generic: new(...) ``` Returns a new set of parametric equation. Equations must be of the form ``` - () = ... + () = ... ``` The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted @@ -485,7 +509,7 @@ as floating point numbers. Example: ``` - x(s) = 2.0 + 3*cos(2*pi*s)^2 + x(s) = 2.0 + 3*cos(2*pi*s)^2 ``` The z-Equation is optional, but for now must define zero for z by default. @@ -495,16 +519,16 @@ A spline is defined by an array of knots, tj,xj,yj Date: Thu, 7 Apr 2022 15:17:42 +0200 Subject: [PATCH 113/164] add quotes to certain code pieces as suggested in review --- docs/src/HQMTool.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 278977ac..6bf5a48d 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -30,7 +30,7 @@ To see that example, run ``` run_demo("out") ``` -where `out` specifies the folder where the resulting mesh and TecPlot files will be saved. +where `"out"` specifies the folder where the resulting mesh and TecPlot files will be saved. The second example builds a new project consisting of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. The "verbose" version of the script is given below. @@ -296,8 +296,8 @@ The run parameters can be enquired and set with these getter/setter pairs: [Return:String] getPlotFileFormat(proj::Project) ``` -The available mesh file formats are `ISM`, `ISM-V2`, or `ABAQUS`. The plot file (which can be viewed with something -like VisIt or Paraview) format is either `skeleton` or `sem`. The former is just a low order finite element +The available mesh file formats are `"ISM"`, `"ISM-V2"`, or `"ABAQUS"`. The plot file (which can be viewed with something +like VisIt or Paraview) format is either `"skeleton"` or `"sem"`. The former is just a low order finite element represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. #### Changing the output file names From 2dc2fe4dd1bde3031eb8f0d1aa272174f4180ac0 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 15:33:10 +0200 Subject: [PATCH 114/164] typo fixes float64 to Float64 --- docs/src/HQMTool.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 6bf5a48d..42f12aff 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -396,9 +396,9 @@ A refinement region can be edited by using the following [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) - [Return:float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:Float64] getRefinementGridSize(r::Dict{String,Any}) [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) - [Return:float64] getRefinementWidth(r::Dict{String,Any}) + [Return:Float64] getRefinementWidth(r::Dict{String,Any}) ``` where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. @@ -429,7 +429,7 @@ To further edit a `RefinementLine`, use the methods Example: ```julia - circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") + circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") add!(p, circ) ``` @@ -446,7 +446,7 @@ To further edit a `RefinementLine`, use the methods Example: ```julia - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) + cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) add!(p, cone1, "IceCreamCone") ``` From 3af695a2c2384877f802d657aa0e70df79210d58 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 15:33:41 +0200 Subject: [PATCH 115/164] make global arrayRegex type stable --- src/Misc/DictionaryOperations.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index 15f91daa..075f216c 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -27,7 +27,7 @@ #= Some useful getters for a dictionary =# -arrayRegex = r"(?<=\[).+?(?=\])" +const arrayRegex = r"(?<=\[).+?(?=\])" function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] From bf52aa728e19dae5f836934498226d50f2c35a5c Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 15:41:01 +0200 Subject: [PATCH 116/164] change Int64 to Int --- src/ControlFile/ControlFileOperations.jl | 74 ++++++++++++------------ src/Curves/CurveOperations.jl | 4 +- src/Misc/DictionaryOperations.jl | 2 +- src/Viz/VizMesh.jl | 52 ++++++++--------- 4 files changed, 62 insertions(+), 70 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index c4c05dfd..cf2f10f0 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -44,7 +44,7 @@ The CONTROL_INPUT contains the blocks MESH_PARAMETERS SPRING_SMOOTHER REFINEMENT_REGIONS - REFINEMENT_REGIONS contains a ["LIST"] of + REFINEMENT_REGIONS contains a ["LIST"] of REFINEMENT_CENTER REFINEMENT_LINE SCALE_TRANSFORMATION @@ -80,15 +80,15 @@ A PARAMETRIC_EQUATION_CURVE dictionary contains the keys xEqn yEqn zEqn - + =# # Four objects store their members as lists rather than # as dictionaries -blocksThatStoreLists = Set(["OUTER_BOUNDARY", +blocksThatStoreLists = Set(["OUTER_BOUNDARY", "REFINEMENT_REGIONS" , - "INNER_BOUNDARIES", + "INNER_BOUNDARIES", "CHAIN"]) blockNameStack = [] @@ -100,9 +100,9 @@ function ImportControlFile(fileName::String) controlDict = Dict{String,Any}() open(fileName,"r") do controlFile performImport(controlDict, controlFile) - end + end return controlDict -end +end function WriteControlFile(controlDict::Dict{String,Any}, fileName::String) open(fileName,"w") do controlFile @@ -137,7 +137,7 @@ function performImport(collection, f::IOStream) if blockName == "SPLINE_DATA" ImportSplineData( collection, f) continue - end + end newBlock = Dict{String,Any}() newBlock["TYPE"] = blockName @@ -157,11 +157,11 @@ function performImport(collection, f::IOStream) error("Key-value pair not found in string: " * nextLine) end addToCollection(newBlock,kvp[1],kvp[2]) - end + end performImport(newBlock["LIST"],f) else performImport(newBlock,f) - end + end end # # -------------- @@ -185,7 +185,7 @@ function performImport(collection, f::IOStream) pop!(blockNameStack) else error("Block name end $blockName does not match current block $stackValue") - end + end if blockName == "SPLINE_DATA" continue else @@ -220,7 +220,7 @@ end # function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::String) - deepIndent = " " * indent + deepIndent = " " * indent for (key, value) in controlDict if isa(value, AbstractDict) println(f,indent,"\\begin{$key}") @@ -229,12 +229,12 @@ function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::Str StepThroughList(list,f, deepIndent) else WriteDictionary(value,f, deepIndent) - end + end println(f,indent,"\\end{$key}") elseif isa(value, AbstractString) if key != "TYPE" println(f,indent,"$key = $value") - end + end elseif isa(value, AbstractArray) if key == "LIST" StepThroughList(value,f, deepIndent) @@ -243,17 +243,17 @@ function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::Str arraySize = size(value) for j = 1:arraySize[1] println(f,deepIndent, " ", value[j,1], " ", value[j,2], " ", value[j,3], " ", value[j,4]) - end + end println(f,indent,"\\end{$key}") - end - end + end + end end end # #-------------------------------------------------------------------------------------- # function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) - deepIndent = " " * indent + deepIndent = " " * indent for dict in lst dtype = dict["TYPE"] println(f,indent, "\\begin{$dtype}") @@ -277,19 +277,19 @@ end #-------------------------------------------------------------------------------------- # function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::AbstractString) - dict[k] = v + dict[k] = v end # #-------------------------------------------------------------------------------------- # function addToCollection(c::Array, k::AbstractString, v::Any) - push!(c,v) + push!(c,v) end # #-------------------------------------------------------------------------------------- # function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::Dict{String,Any}) - dict[k] = v + dict[k] = v end # #-------------------------------------------------------------------------------------- @@ -301,13 +301,13 @@ function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) end knotString = splineDict["nKnots"] - nKnots = parse(Int64,knotString) - splineDataArray = zeros(Float64,nKnots,4) + nKnots = parse(Int, knotString) + splineDataArray = zeros(Float64, nKnots, 4) for i = 1:nKnots currentLine = split(readline(f)) for j = 1:4 - splineDataArray[i,j] = parse(Float64,currentLine[j]) + splineDataArray[i,j] = parse(Float64, currentLine[j]) end - end + end splineDict["SPLINE_DATA"] = splineDataArray end diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index b81ede7f..eed96c1b 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -24,9 +24,7 @@ --- End License =# -using Base: String, Int64, Float64 - -argRegex = r"(?<=\().+?(?=\))" +const argRegex = r"(?<=\().+?(?=\))" function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Array{Float64}, points::Array{Float64,2}) fctr::Float64 = 1.0 diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index 075f216c..6af93dd8 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -36,7 +36,7 @@ end function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] - return parse(Int64,v) + return parse(Int,v) end function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index 9e990698..de0d6b4f 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -32,23 +32,23 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS line = readline(f) # Numbers of nodes, edges ... values = split(line) - nNodes = parse(Int,values[1]) - nEdges = parse(Int,values[2]) + nNodes = parse(Int, values[1]) + nEdges = parse(Int, values[2]) # # Read the nodes # - nodes = zeros(Float64,nNodes,2) + nodes = zeros(Float64, nNodes, 2) for i = 1:nNodes values = split(readline(f)) for j = 1:2 - nodes[i,j] = parse(Float64,values[j]) + nodes[i,j] = parse(Float64, values[j]) end end # # Read the edges and construct the lines array # - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) + xMesh = zeros(Float64, 3*nEdges) + yMesh = zeros(Float64, 3*nEdges) for i = 1:3:3*nEdges @@ -68,18 +68,18 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS return xMesh, yMesh end elseif meshFileFormat == "ISM" - open(meshFile,"r") do f + open(meshFile, "r") do f # There is no header line = readline(f) # Numbers of corners, elements and boundary polynomial order values = split(line) - nNodes = parse(Int,values[1]) - nElements = parse(Int,values[2]) + nNodes = parse(Int, values[1]) + nElements = parse(Int, values[2]) nBndy = parse(Int, values[3]) # # Read the nodes # - nodes = zeros(Float64,nNodes,2) + nodes = zeros(Float64, nNodes, 2) for i = 1:nNodes values = split(readline(f)) for j = 1:2 @@ -89,16 +89,16 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # # Read the element ids (and skip all the boundary information) # - elements = zeros(Int64,nElements,4) - temp = zeros(Int64, 4) + elements = zeros(Int,nElements,4) + temp = zeros(Int, 4) for i = 1:nElements values = split(readline(f)) for j = 1:4 - elements[i,j] = parse(Int64, values[j]) + elements[i,j] = parse(Int, values[j]) end values = split(readline(f)) for j = 1:4 - temp[j] = parse(Int64, values[j]) + temp[j] = parse(Int, values[j]) end if sum(temp) == 0 # straight-sided edge so just skip the boundary labels @@ -119,23 +119,20 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # Build the edges. This is only for plotting purposes so we might have some # repeated edges edge_id = 0 - #hash_table = Dict{Int, Int}() edges = Dict{Int, Any}() for j in 1:nElements for k in 1:4 id1 = elements[j , p[1,k]] id2 = elements[j , p[2,k]] - key_val = id1 + id2 edge_id += 1 - #push!( hash_table , key_val => edge_id ) - push!( edges , edge_id => [id1 id2] ) + push!(edges, edge_id => [id1 id2]) end # k end # j # set the total number of edges nEdges = edge_id # use the edge information and pull the corner node physical values - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) + xMesh = zeros(Float64, 3*nEdges) + yMesh = zeros(Float64, 3*nEdges) edge_id = 0 for i = 1:3:3*nEdges edge_id += 1 @@ -168,7 +165,7 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # # Read in the nodes # - nodes = zeros(Float64,nNodes,2) + nodes = zeros(Float64, nNodes, 2) file_idx = 4 for i in 1:nNodes current_line = split(file_lines[file_idx], ",") @@ -180,13 +177,13 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # # Read the element ids (and skip all the boundary information) # - elements = zeros(Int64,nElements,4) + elements = zeros(Int, nElements, 4) # eat the element header file_idx += 1 for i = 1:nElements current_line = split(file_lines[file_idx], ",") for j = 2:5 - elements[i,j-1] = parse(Int64, current_line[j]) + elements[i,j-1] = parse(Int, current_line[j]) end file_idx += 1 end @@ -196,23 +193,20 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # Build the edges. This is only for plotting purposes so we might have some # repeated edges edge_id = 0 - #hash_table = Dict{Int, Int}() edges = Dict{Int, Any}() for j in 1:nElements for k in 1:4 id1 = elements[j , p[1,k]] id2 = elements[j , p[2,k]] - key_val = id1 + id2 edge_id += 1 - #push!( hash_table , key_val => edge_id ) - push!( edges , edge_id => [id1 id2] ) + push!(edges, edge_id => [id1 id2]) end # k end # j # set the total number of edges nEdges = edge_id # use the edge information and pull the corner node physical values - xMesh = zeros(Float64,3*nEdges) - yMesh = zeros(Float64,3*nEdges) + xMesh = zeros(Float64, 3*nEdges) + yMesh = zeros(Float64, 3*nEdges) edge_id = 0 for i = 1:3:3*nEdges edge_id += 1 From cf173d65ff08e6439ef41a419f99a7740c216e65 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 16:04:05 +0200 Subject: [PATCH 117/164] use Perl style string concatenation for literals --- src/Project/BackgroundGridAPI.jl | 6 +- src/Project/CurvesAPI.jl | 88 ++++++++++++++--------------- src/Project/RefinementRegionsAPI.jl | 6 +- 3 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 35bb44a8..64f25377 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -199,7 +199,7 @@ function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") end - x0Str = @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) + x0Str = "[$(x0[1]),$(x0[2]),$(x0[3])]" # @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) bgDict["x0"] = x0Str postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing @@ -219,7 +219,7 @@ function setBackgroundGridSteps!(proj::Project, N::Array{Int}) (oldN[1],oldN[2],oldN[3]),"Set Background Steps") end - NStr = @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) + NStr = "[$(N[1]),$(N[2]),$(N[3])]" # @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) bgDict["N"] = NStr postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -244,7 +244,7 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::Str (oldDx[1],oldDx[2],oldDx[3]),"Set Background Size") end - dxStr = @sprintf("[%f,%f,%f]", dx, dy, 0.0) + dxStr = "[$(dx),$(dy),$(0.0)]" # @sprintf("[%f,%f,%f]", dx, dy, 0.0) bgDict[key] = dxStr postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 54d41d82..0323dee6 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -3,38 +3,38 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# """ - newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, + newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) Creates and returns a new parametricEquationCurve in the form of a Dictionary """ -function newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, +function newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, zEqn::String = "z(t) = 0.0" ) crv = Dict{String,Any}() @@ -54,7 +54,7 @@ end Creates and returns a new curve defined by its end points in the form of a Dictionary """ -function newEndPointsLineCurve(name::String, +function newEndPointsLineCurve(name::String, xStart::Array{Float64}, xEnd::Array{Float64}) crv = Dict{String,Any}() @@ -69,19 +69,19 @@ function newEndPointsLineCurve(name::String, return crv end """ - newCircularArcCurve(name::String, center::Array{Float64}, + newCircularArcCurve(name::String, center::Array{Float64}, startAngle::Float64, endAngle::Float64, units::String) Creates and returns a new circular arc curve in the form of a Dictionary """ -function newCircularArcCurve(name::String, - center::Array{Float64}, +function newCircularArcCurve(name::String, + center::Array{Float64}, radius::Float64, - startAngle::Float64, + startAngle::Float64, endAngle::Float64, units::String = "degrees") - + arc = Dict{String,Any}() arc["TYPE"] = "CIRCULAR_ARC" disableNotifications() @@ -130,9 +130,9 @@ function newSplineCurve(name::String, dataFile::String) for j = 1:4 splineDataArray[i,j] = parse(Float64,currentLine[j]) end - end + end spline = newSplineCurve(name, nKnots, splineDataArray) - end + end return spline end #""" @@ -159,7 +159,7 @@ Set the name of the curve represented by curveDict. function setCurveName!(crv::Dict{String,Any}, name::String) if haskey(crv,"name") oldName = crv["name"] - registerWithUndoManager(crv,setCurveName!, (oldName,), "Set Curve Name") + registerWithUndoManager(crv,setCurveName!, (oldName,), "Set Curve Name") postNotificationWithName(crv,"CURVE_DID_CHANGE_NAME_NOTIFICATION",(oldName,)) end crv["name"] = name @@ -187,7 +187,7 @@ For a parametric equation, set the x-equation. function setXEqn!(crv::Dict{String,Any}, eqn::String) if haskey(crv,"xEqn") oldEqn = crv["xEqn"] - registerWithUndoManager(crv,setXEqn!, (eqn,), "Set X Equation") + registerWithUndoManager(crv,setXEqn!, (eqn,), "Set X Equation") end crv["xEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -209,7 +209,7 @@ For a parametric equation, set the y-equation. function setYEqn!(crv::Dict{String,Any}, eqn::String) if haskey(crv,"yEqn") oldEqn = crv["yEqn"] - registerWithUndoManager(crv,setYEqn!, (eqn,), "Set Y Equation") + registerWithUndoManager(crv,setYEqn!, (eqn,), "Set Y Equation") end crv["yEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -231,7 +231,7 @@ For a parametric equation, set the zEqn-equation. function setZEqn!(crv::Dict{String,Any}, eqn::String) if haskey(crv,"zEqn") oldEqn = crv["zEqn"] - registerWithUndoManager(crv,setZEqn!, (eqn,), "Set Z Equation") + registerWithUndoManager(crv,setZEqn!, (eqn,), "Set Z Equation") end crv["zEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -251,7 +251,7 @@ end Set the start point for a line curve. """ function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) setStartPoint!(crv,pStr) end @@ -259,7 +259,7 @@ function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xStart" if haskey(crv,key) oldPt = crv[key] - registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") + registerWithUndoManager(crv,setStartPoint!, (oldPt,), "Set Start Point") end crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -278,7 +278,7 @@ end Set the end point for a line curve. """ function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) setEndPoint!(crv,pStr) end @@ -286,7 +286,7 @@ function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xEnd" if haskey(crv,key) oldPt = crv[key] - registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") + registerWithUndoManager(crv,setEndPoint!, (oldPt,), "Set End Point") end crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -309,10 +309,10 @@ function setArcUnits!(arc::Dict{String,Any}, units::String) key = "units" if haskey(arc,key) oldUnits = arc[key] - registerWithUndoManager(arc,setArcUnits!, (oldUnits,), "Set Arc Units") + registerWithUndoManager(arc,setArcUnits!, (oldUnits,), "Set Arc Units") end arc[key] = units - postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) + postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) else println("Units must either be `degrees` or `radians`. Try setting `units` again.") end @@ -331,14 +331,14 @@ end Set the center of a circular arc. """ function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - pStr = @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) setArcCenter!(arc,pStr) end function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) key = "center" if haskey(arc,key) oldVal = arc[key] - registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") + registerWithUndoManager(arc,setArcCenter!, (oldVal,), "Set Arc Center") end arc[key] = pointAsString @@ -360,7 +360,7 @@ function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) key = "start angle" if haskey(arc,key) oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcStartAngle!, (oldVal,), "Set Arc Start Angle") + registerWithUndoManager(arc,setArcStartAngle!, (oldVal,), "Set Arc Start Angle") end arc[key] = string(angle) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -380,7 +380,7 @@ function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) key = "end angle" if haskey(arc,key) oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcEndAngle!, (oldVal,), "Set Arc Start Angle") + registerWithUndoManager(arc,setArcEndAngle!, (oldVal,), "Set Arc Start Angle") end arc[key] = string(angle) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -400,7 +400,7 @@ function setArcRadius!(arc::Dict{String,Any}, radius::Float64) key = "radius" if haskey(arc,key) oldVal = parse(Float64,arc[key]) - registerWithUndoManager(arc,setArcRadius!, (oldVal,), "Set Arc Radius") + registerWithUndoManager(arc,setArcRadius!, (oldVal,), "Set Arc Radius") end arc[key] = string(radius) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -419,7 +419,7 @@ function setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) key = "nKnots" if haskey(spline,key) oldVal = parse(Int,spline[key]) - registerWithUndoManager(spline,setSplineNKnots!, (oldVal,), "Set Spline Knots") + registerWithUndoManager(spline,setSplineNKnots!, (oldVal,), "Set Spline Knots") end spline["nKnots"] = string(nKnots) postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -436,7 +436,7 @@ end function setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) key = "SPLINE_DATA" if haskey(spline,key) - registerWithUndoManager(spline,setSplinePoints!, (spline["SPLINE_DATA"],), "Set Spline Points") + registerWithUndoManager(spline,setSplinePoints!, (spline["SPLINE_DATA"],), "Set Spline Points") end spline["SPLINE_DATA"] = points postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 4bc6815a..9058f3ae 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -305,7 +305,7 @@ end# Set the location of a refinement center to location = [x,y,z]. """ function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) setRefinementLocation!(r,x0Str) return nothing end @@ -408,7 +408,7 @@ end Set the start point location of a refinement line, `location = [x, y, z]`. """ function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) setRefinementStart!(r,x0Str) end @@ -441,7 +441,7 @@ end Set the end point location of a refinement line, `location = [x, y, z]`. """ function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) setRefinementEnd!(r,x0Str) end From 4c5e035c75b0473311a8a74a2224d21f09f34f61 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 7 Apr 2022 16:12:19 +0200 Subject: [PATCH 118/164] Remove dependency of Printf with Perl style concatenation --- Project.toml | 1 - src/HOHQMesh.jl | 1 - src/Project/BackgroundGridAPI.jl | 6 +++--- src/Project/CurvesAPI.jl | 6 +++--- src/Project/RefinementRegionsAPI.jl | 6 +++--- 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Project.toml b/Project.toml index 93128bb2..092c5a27 100644 --- a/Project.toml +++ b/Project.toml @@ -5,7 +5,6 @@ version = "0.1.2-pre" [deps] HOHQMesh_jll = "1d5cbd98-5122-5a8a-bea1-c186d986ee7f" -Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Requires = "ae029012-a4dd-5104-9daa-d747884805df" [compat] diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 7cd6ede1..9498e6c0 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -4,7 +4,6 @@ module HOHQMesh # (standard library packages first, other packages next, all of them sorted alphabetically) using HOHQMesh_jll: HOHQMesh_jll -using Printf using Requires: @require function __init__() diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 64f25377..8443dec2 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -199,7 +199,7 @@ function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) (oldLowerLeft[1],oldLowerLeft[2],0.0),"Set Background Lower Left") end - x0Str = "[$(x0[1]),$(x0[2]),$(x0[3])]" # @sprintf("[%f,%f,%f]", x0[1], x0[2], x0[3]) + x0Str = "[$(x0[1]),$(x0[2]),$(x0[3])]" bgDict["x0"] = x0Str postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing @@ -219,7 +219,7 @@ function setBackgroundGridSteps!(proj::Project, N::Array{Int}) (oldN[1],oldN[2],oldN[3]),"Set Background Steps") end - NStr = "[$(N[1]),$(N[2]),$(N[3])]" # @sprintf("[%i,%i,%i]", N[1], N[2], N[3]) + NStr = "[$(N[1]),$(N[2]),$(N[3])]" bgDict["N"] = NStr postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -244,7 +244,7 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::Str (oldDx[1],oldDx[2],oldDx[3]),"Set Background Size") end - dxStr = "[$(dx),$(dy),$(0.0)]" # @sprintf("[%f,%f,%f]", dx, dy, 0.0) + dxStr = "[$(dx),$(dy),$(0.0)]" bgDict[key] = dxStr postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 0323dee6..f92dc19f 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -251,7 +251,7 @@ end Set the start point for a line curve. """ function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" setStartPoint!(crv,pStr) end @@ -278,7 +278,7 @@ end Set the end point for a line curve. """ function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" setEndPoint!(crv,pStr) end @@ -331,7 +331,7 @@ end Set the center of a circular arc. """ function setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - pStr = "[$(point[1]),$(point[2]),$(point[3])]" # @sprintf("[%f,%f,%f]", point[1], point[2], point[3]) + pStr = "[$(point[1]),$(point[2]),$(point[3])]" setArcCenter!(arc,pStr) end function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 9058f3ae..ed9f8e2d 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -305,7 +305,7 @@ end# Set the location of a refinement center to location = [x,y,z]. """ function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" setRefinementLocation!(r,x0Str) return nothing end @@ -408,7 +408,7 @@ end Set the start point location of a refinement line, `location = [x, y, z]`. """ function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" setRefinementStart!(r,x0Str) end @@ -441,7 +441,7 @@ end Set the end point location of a refinement line, `location = [x, y, z]`. """ function setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - x0Str = "[$(x[1]),$(x[2]),$(x[3])]" # @sprintf("[%f,%f,%f]", x[1], x[2], x[3]) + x0Str = "[$(x[1]),$(x[2]),$(x[3])]" setRefinementEnd!(r,x0Str) end From 38343ea9ffb2d52b1ed10bbdbb4d7ac6b94e65e7 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 13:04:31 +0200 Subject: [PATCH 119/164] set constants for better type stability --- src/ControlFile/ControlFileOperations.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index cf2f10f0..e44f5d11 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -86,13 +86,13 @@ A PARAMETRIC_EQUATION_CURVE dictionary contains the keys # Four objects store their members as lists rather than # as dictionaries -blocksThatStoreLists = Set(["OUTER_BOUNDARY", - "REFINEMENT_REGIONS" , - "INNER_BOUNDARIES", - "CHAIN"]) +const blocksThatStoreLists = Set(["OUTER_BOUNDARY", + "REFINEMENT_REGIONS" , + "INNER_BOUNDARIES", + "CHAIN"]) +const blockRegex = r"(?<=\{).+?(?=\})" blockNameStack = [] -blockRegex = r"(?<=\{).+?(?=\})" # #--------------- MAIN ENTRY ----------------------------------------------- # From df2cb4ef064a145bfaae2eb705e601e3f97bde6b Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 13:05:05 +0200 Subject: [PATCH 120/164] export plotting constants for better user experience --- src/HOHQMesh.jl | 3 +++ test/test_project_with_viz.jl | 4 ++-- test/test_visualization.jl | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 9498e6c0..87c1a9a6 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -12,7 +12,10 @@ function __init__() using .Makie include("Viz/VizProject.jl") include("Viz/VizMesh.jl") + # Make the actual plotting routines available export plotProject!, updatePlot! + # Make plotting constants available for easier use + export MODEL, GRID, MESH, EMPTY, REFINEMENTS, ALL end end diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index e404fec3..8f446fcb 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -21,7 +21,7 @@ using CairoMakie # Lay the background grid and plot it addBackgroundGrid!(p_scratch, bounds, N) - plotProject!(p_scratch, HOHQMesh.GRID) + plotProject!(p_scratch, GRID) # Build the outer boundary chain and plot piece-by-piece outer_line1 = newEndPointsLineCurve("outerline1", [0.0, -7.0, 0.0], [4.0, 3.0, 0.0]) @@ -69,7 +69,7 @@ using CairoMakie control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p_file = openProject(control_file, projectPath) - @test_nowarn plotProject!(p_file, HOHQMesh.MODEL + HOHQMesh.GRID) + @test_nowarn plotProject!(p_file, MODEL+GRID) # Refinement regions are already present but we manually adjust # one of its parameters to trigger a specific piece of plot update logic diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 0a52bc08..edb706a0 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -56,7 +56,7 @@ using CairoMakie setFileNames!(p_visu, meshFileFormat) # Show initial the model and grid - @test_nowarn plotProject!(p_visu, HOHQMesh.MODEL + HOHQMesh.GRID) + @test_nowarn plotProject!(p_visu, MODEL+GRID) # Create the mesh which contains a plotting update for ISM @test_nowarn generate_mesh(p_visu) @@ -111,7 +111,7 @@ using CairoMakie meshFileFormat = getMeshFileFormat(p_visu) setFileNames!(p_visu, meshFileFormat) - @test_nowarn updatePlot!(p_visu, HOHQMesh.MODEL + HOHQMesh.GRID + HOHQMesh.REFINEMENTS) + @test_nowarn updatePlot!(p_visu, MODEL+GRID+REFINEMENTS) # Create the mesh which contains a plotting update for ABAQUS @test_nowarn generate_mesh(p_visu) From d83af6ea96601ab6f8c0e859c7e44e4d16b72bb0 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 13:39:09 +0200 Subject: [PATCH 121/164] adjust includes. Now only the main module has them --- src/HOHQMesh.jl | 32 ++++++++++++++++----- src/Project/ModelAPI.jl | 62 ++++++++++++++++++++++++++--------------- src/Project/Project.jl | 19 ++++--------- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 87c1a9a6..6ab5a6c3 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -304,18 +304,36 @@ Return the path to the directory with some example mesh setups. examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") -# Include functionality for interactive reading, writing, and plotting of a model for HOHQMesh -include("Viz/VizMesh.jl") -include("Misc/NotificationCenter.jl") -include("Misc/DictionaryOperations.jl") -include("Curves/Spline.jl") +# +# Include functionality for interactive reading and writing a model for HOHQMesh +# Note, The visualzation routines are included above in the `__init__` above because +# Makie is required +# + +# Core interactive tool routines for control file readin, curve evaluation, etc. include("ControlFile/ControlFileOperations.jl") include("Curves/CurveOperations.jl") +include("Curves/Spline.jl") +include("Misc/DictionaryOperations.jl") +include("Misc/NotificationCenter.jl") +include("Model/Geometry.jl") + +# Project itself and some helper generic and undo functionality include("Project/Project.jl") -include("Project/CurvesAPI.jl") +include("Project/Generics.jl") include("Project/Undo.jl") + +# Front facing API of the interactive tool for the `Project` +include("Project/BackgroundGridAPI.jl") +include("Project/ControlInputAPI.jl") +include("Project/CurvesAPI.jl") +include("Project/ModelAPI.jl") +include("Project/RefinementRegionsAPI.jl") +include("Project/RunParametersAPI.jl") +include("Project/SmootherAPI.jl") + +# Main routine that uses HOHQMesh to generate a mesh from an interactive `Project` include("Mesh/Meshing.jl") -include("Project/Generics.jl") # #---------------- Routines for demonstrating the HQMTool --------------------------------- diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index c9458492..80eb6789 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -24,10 +24,10 @@ --- End License =# -include("../Model/Geometry.jl") - # # -------------------------------------------------------------------------------------- +# OUTER BOUNDARY FUNCTIONS +# -------------------------------------------------------------------------------------- # """ addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) @@ -61,6 +61,8 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Outer Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ removeOuterBoundaryCurveWithName!(proj::Project, name::String) @@ -74,6 +76,8 @@ function removeOuterBoundaryCurveWithName!(proj::Project, name::String) removeOuterBoundaryCurveAtIndex!(proj,indx) # posts undo/notification end end + + """ getOuterBoundaryCurveWithName(proj::Project, name::String) """ @@ -85,10 +89,12 @@ function getOuterBoundaryCurveWithName(proj::Project, name::String) end end end + + """ - insertOuterBoundaryCurveAtIndex(proj::Project, crv::Dict{String,Any}, indx::Int) + insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) -Insert a curve at the specified index. +Insert a curve into the outer boundary chain at the specified index. """ function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) lst = getOuterBoundaryChainList(proj) @@ -100,6 +106,11 @@ function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end +""" + removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) + +Remove a curve from the outer boundary chain at the specified index. +""" function removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) lst = getOuterBoundaryChainList(proj) crv = lst[indx] @@ -131,6 +142,8 @@ function addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) registerWithUndoManager(proj,removeOuterBoundary!, (nothing,), "Add Outer Boundary") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ removeOuterboundary!(proj::Project) @@ -150,13 +163,13 @@ function removeOuterBoundary!(proj::Project) end end + # function addOuterBoundary(proj::Project,obDict::Dict{String,Any}) # modelDict = getModelDict(proj) # modelDict["OUTER_BOUNDARY"] = obDict # end -# -# -------------------------------------------------------------------------------------- -# + + """ getOuterBoundaryChainList(proj::Project) @@ -173,6 +186,7 @@ function getOuterBoundaryChainList(proj::Project) return lst end end + # # -------------------------------------------------------------------------------------- # INNER BOUNDARY FUNCTIONS @@ -219,6 +233,8 @@ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundary "Add Inner Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ removeInnerBoundaryCurve!(proj::Project, name::String) @@ -284,6 +300,8 @@ function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::S postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end end + + """ removeInnerBoundary!(proj::Project, chainName::String) @@ -302,6 +320,8 @@ function removeInnerBoundary!(proj::Project, chainName::String) deleteat!(ibChains,i) postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ insertInnerBoundaryAtIndex!(proj::Project, chainName::String, indx::Int, chain::??) @@ -320,9 +340,8 @@ function insertInnerBoundaryAtIndex!(proj::Project, chainName::String, i::Int, c "Remove Inner Boundary") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end -# -# -------------------------------------------------------------------------------------- -# + + """ addInnerBoundaryWithName!(proj::Project,name::String) @@ -349,9 +368,8 @@ function addInnerBoundaryWithName!(proj::Project,name::String) return bndryChain end -# -#---------------------------------------------------------------------------------------- -# + + function getChainIndex(chain::Vector{Dict{String, Any}},name) for (i,dict) in enumerate(chain) if dict["name"] == name @@ -365,9 +383,8 @@ end Returns an array of the inner boundaries """ -# -# -------------------------------------------------------------------------------------- -# + + function getAllInnerBoundaries(proj::Project) innerBndryDict = getDictInModelDictNamed(proj,"INNER_BOUNDARIES") if haskey(innerBndryDict,"LIST") @@ -380,9 +397,8 @@ function getAllInnerBoundaries(proj::Project) end return nothing end -# -# -------------------------------------------------------------------------------------- -# + + """ getInnerBoundaryWithName(proj::Project, name::String) @@ -425,6 +441,8 @@ function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::S println("No curve ", curveName, " in boundary ", boundaryName, ". Try again.") return nothing end + + """ innerBoundaryIndices(proj::Project, curveName::String) @@ -446,9 +464,8 @@ function innerBoundaryIndices(proj::Project, curveName::String) end return (0,0) end -# -# -------------------------------------------------------------------------------------- -# + + function getModelDict(proj::Project) if haskey(proj.projectDictionary,"MODEL") return proj.projectDictionary["MODEL"] @@ -460,6 +477,7 @@ function getModelDict(proj::Project) end end + function getDictInModelDictNamed(proj::Project,name::String) modelDict = getModelDict(proj) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index e23fef01..7c1fd392 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -55,19 +55,12 @@ mutable struct Project meshShouldUpdate ::Bool end -defaultPlotPts = 50 -meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) -plotFileFormats = Set(["sem", "skeleton"]) -smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) -statusValues = Set(["ON", "OFF"]) -refinementTypes = Set(["smooth", "sharp"]) - -include("./ControlInputAPI.jl") -include("./BackgroundGridAPI.jl") -include("./ModelAPI.jl") -include("./RefinementRegionsAPI.jl") -include("./RunParametersAPI.jl") -include("./SmootherAPI.jl") +const defaultPlotPts = 50 +const meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) +const plotFileFormats = Set(["sem", "skeleton"]) +const smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) +const statusValues = Set(["ON", "OFF"]) +const refinementTypes = Set(["smooth", "sharp"]) """ openProject(fileName::String, folder::String) From e3b855530fed37f4840bad3e2f62c4a93209fffc Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 13:58:58 +0200 Subject: [PATCH 122/164] adjust spacing throughout between functions to make code easier to read --- src/ControlFile/ControlFileOperations.jl | 38 ++++--- src/Curves/CurveOperations.jl | 13 +++ src/Curves/Spline.jl | 39 +++---- src/HOHQMesh.jl | 3 + src/Mesh/Meshing.jl | 1 + src/Misc/DictionaryOperations.jl | 7 ++ src/Misc/NotificationCenter.jl | 5 + src/Model/Geometry.jl | 37 ++++--- src/Project/BackgroundGridAPI.jl | 20 ++++ src/Project/ControlInputAPI.jl | 28 ++--- src/Project/CurvesAPI.jl | 87 +++++++++++++--- src/Project/Generics.jl | 12 +++ src/Project/ModelAPI.jl | 4 + src/Project/Project.jl | 19 ++++ src/Project/RefinementRegionsAPI.jl | 124 ++++++++++++----------- src/Project/RunParametersAPI.jl | 21 ++++ src/Project/SmootherAPI.jl | 55 ++++++---- src/Project/Undo.jl | 38 ++++--- src/Viz/VizMesh.jl | 1 + src/Viz/VizProject.jl | 21 ++-- 20 files changed, 388 insertions(+), 185 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index e44f5d11..651e0cab 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -93,6 +93,7 @@ const blocksThatStoreLists = Set(["OUTER_BOUNDARY", const blockRegex = r"(?<=\{).+?(?=\})" blockNameStack = [] + # #--------------- MAIN ENTRY ----------------------------------------------- # @@ -104,6 +105,7 @@ function ImportControlFile(fileName::String) return controlDict end + function WriteControlFile(controlDict::Dict{String,Any}, fileName::String) open(fileName,"w") do controlFile indent = "" @@ -114,6 +116,7 @@ end # #------------- END MAIN ENTRY ------------------------------------------ # + function performImport(collection, f::IOStream) for line in eachline(f) @@ -215,9 +218,8 @@ function performImport(collection, f::IOStream) end end end -# -#-------------------------------------------------------------------------------------- -# + + function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::String) deepIndent = " " * indent @@ -249,9 +251,8 @@ function WriteDictionary(controlDict::Dict{String,Any}, f::IOStream, indent::Str end end end -# -#-------------------------------------------------------------------------------------- -# + + function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) deepIndent = " " * indent for dict in lst @@ -261,9 +262,8 @@ function StepThroughList(lst::AbstractArray,f::IOStream, indent::String) println(f,indent, "\\end{$dtype}") end end -# -#-------------------------------------------------------------------------------------- -# + + function keyAndValueOnLine(s) indxOfEqual = findfirst("=",s) if indxOfEqual === nothing @@ -273,27 +273,23 @@ function keyAndValueOnLine(s) value = strip(s[indxOfEqual.stop+1:end],[' ','\t']) return (key,value) end -# -#-------------------------------------------------------------------------------------- -# + + function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::AbstractString) dict[k] = v end -# -#-------------------------------------------------------------------------------------- -# + + function addToCollection(c::Array, k::AbstractString, v::Any) push!(c,v) end -# -#-------------------------------------------------------------------------------------- -# + + function addToCollection(dict::Dict{String,Any}, k::AbstractString, v::Dict{String,Any}) dict[k] = v end -# -#-------------------------------------------------------------------------------------- -# + + function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) if !haskey(splineDict, "nKnots") diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index eed96c1b..7e40d732 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -40,6 +40,7 @@ function arcCurvePoints(center::Array{Float64}, r::Float64, thetaStart::Float64, end end + function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, thetaEnd::Float64, units::AbstractString, t::Float64, point::Array{Float64}) fctr::Float64 = 1.0 @@ -51,16 +52,19 @@ function arcCurvePoint(center::Array{Float64}, r::Float64, thetaStart::Float64, point[2] = center[2] + r*sin(theta*fctr) end + function endPointsLineCurvePoints(xStart::Array{Float64}, xEnd::Array{Float64}, t::Array{Float64}, points::Array{Float64}) for i = 1:length(t) points[i,1:2] = xStart[1:2] + t[i]*(xEnd[1:2] - xStart[1:2]) end end + function endPointsLineCurvePoint(xStart::Array{Float64}, xEnd::Array{Float64}, t::Float64, point::Array{Float64}) point[1:2] = xStart[1:2] + t*(xEnd[1:2] - xStart[1:2]) end + function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Float64,2}) argPart,eqString = keyAndValueFromString(xEqn) @@ -79,6 +83,7 @@ function peEquationCurvePoints(xEqn, yEqn, t::Array{Float64}, points::Array{Floa end end + function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) argPart,eqString = keyAndValueFromString(xEqn) @@ -96,6 +101,7 @@ function peEquationCurvePoint(xEqn, yEqn, t::Float64, point::Array{Float64}) end + function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Array{Float64,2}) xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) @@ -111,6 +117,7 @@ function splineCurvePoints(nKnots::Int, splineData::Array{Float64,2}, points::Ar end end + function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::Array{Float64}) xSpline = constructSpline(nKnots,splineData[:,1],splineData[:,2]) @@ -120,6 +127,7 @@ function splineCurvePoint(nKnots::Int, splineData::Array{Float64,2}, t, point::A point[2] = evalSpline(ySpline,t) end + # This function evaluates a string as an equation, might be redundant code # function parse_eval_dict(s::AbstractString, locals::Dict{Symbol}) # ex = Meta.parse(s) @@ -127,11 +135,13 @@ end # eval(:(let $(assignments...); $ex; end)) # end + function evalWithDict(ex, locals::Dict{Symbol}) assignments = [:($sym = $val) for (sym,val) in locals] eval(:(let $(assignments...); $ex; end)) end + function curvePoints(crvDict::Dict{String,Any}, N::Int) # N = Number of intervals curveType::String = crvDict["TYPE"] @@ -186,6 +196,7 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) return x end + function chainPoints(chain::Array{Dict{String,Any}}, N::Int) x = Any[] @@ -196,6 +207,7 @@ function chainPoints(chain::Array{Dict{String,Any}}, N::Int) return x end + function curvePoint(crvDict::Dict{String,Any}, t::Float64) curveType::String = crvDict["TYPE"] @@ -227,6 +239,7 @@ function curvePoint(crvDict::Dict{String,Any}, t::Float64) return x end + function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}) xFirst = curvePoint(firstCurve,1.0) xSecond = curvePoint(secondCurve,0.0) diff --git a/src/Curves/Spline.jl b/src/Curves/Spline.jl index 6d34f47a..2e5478bd 100644 --- a/src/Curves/Spline.jl +++ b/src/Curves/Spline.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -38,7 +38,7 @@ function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) b = zeros(Float64,N) c = zeros(Float64,N) d = zeros(Float64,N) - + Nm1 = N - 1 # # Set up tri-diagonal system @@ -76,7 +76,7 @@ function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) for ib = 1:Nm1 i = N - ib c[i] = (c[i] - d[i]*c[i+1])/b[i] - end + end # # Compute polynomial coefficients # @@ -85,14 +85,15 @@ function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) b[i] = (y[i+1] - y[i])/d[i] - d[i]*(c[i+1] + 2.0*c[i]) d[i] = (c[i+1] - c[i])/d[i] c[i] = 3.0*c[i] - end + end c[N] = 3.0*c[N] d[N] = d[N-1] - + spl = Spline(N,x,y,b,c,d,1) return spl end + function evalSpline(spl::Spline, u::Float64) N = spl.N s = 0.0 @@ -112,7 +113,7 @@ function evalSpline(spl::Spline, u::Float64) i = 1 j = N+1 - for ii = 1:N + for ii = 1:N k = div(i+j,2) if u < spl.x[k] j = k @@ -128,4 +129,4 @@ function evalSpline(spl::Spline, u::Float64) s = spl.y[i] + dx*(spl.b[i]+ dx*(spl.c[i] + dx*spl.d[i])) spl.last = i return s -end \ No newline at end of file +end diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 6ab5a6c3..ea1c10ba 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -356,6 +356,7 @@ function run_demo(folder::String; called_by_user=true) return p end + function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, @@ -401,6 +402,7 @@ function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) return p end + function ice_cream_cone_demo(folder::String; called_by_user=true) # # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, @@ -447,4 +449,5 @@ function ice_cream_cone_demo(folder::String; called_by_user=true) return p end + end # module diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 9d62732c..6e0b83bf 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -41,6 +41,7 @@ function generate_mesh(proj::Project) return nothing end + function remove_mesh!(proj::Project) meshFile = getMeshFileName(proj) rm(meshFile) diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index 6af93dd8..ae3e5863 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -27,6 +27,7 @@ #= Some useful getters for a dictionary =# + const arrayRegex = r"(?<=\[).+?(?=\])" function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) @@ -34,16 +35,19 @@ function realForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) return parse(Float64,v) end + function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] return parse(Int,v) end + function stringForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] return v end + function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] values = match(arrayRegex,v) @@ -52,6 +56,7 @@ function realArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) return array end + function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] values = match(arrayRegex,v) @@ -60,6 +65,7 @@ function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) return array end + function keyAndValueFromString(s) indxOfEqual = findfirst("=",s) if indxOfEqual === nothing @@ -70,6 +76,7 @@ function keyAndValueFromString(s) return (key,value) end + function showDescription(d::Dict, pre=1) todo = Vector{Tuple}() for (k,v) in d diff --git a/src/Misc/NotificationCenter.jl b/src/Misc/NotificationCenter.jl index 98561908..f6227497 100644 --- a/src/Misc/NotificationCenter.jl +++ b/src/Misc/NotificationCenter.jl @@ -37,6 +37,7 @@ end HQMNotificationCenter = Dict{String,Vector{HQMNotificationObject}}() HQMNotificationsON = true + """ addObserver(observer::Any, note::String, fnction::Any) @@ -55,6 +56,7 @@ function addObserver(observer::Any, note::String, fnction::Any) push!(HQMNotificationCenter[note],noteObj) end + """ unRegisterForNotification(observer::Any, note::String) @@ -78,6 +80,7 @@ function unRegisterForNotification(observer::Any, note::String) end end + """ postNotificationWithName(sender::Any, name::String, userInfo::Tuple) @@ -100,10 +103,12 @@ function postNotificationWithName(sender::Any, note::String, userInfo::Tuple) end end + function enableNotifications() global HQMNotificationsON = true end + function disableNotifications() global HQMNotificationsON = false end diff --git a/src/Model/Geometry.jl b/src/Model/Geometry.jl index 71a99954..efbeea7e 100644 --- a/src/Model/Geometry.jl +++ b/src/Model/Geometry.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -38,7 +38,7 @@ function curveBounds(crvPoints::Array{Float64,2}) left = Inf64 bottom = Inf64 right = -Inf64 - + for i = 1:s[1] right = max(right,crvPoints[i,1]) left = min(left,crvPoints[i,1]) @@ -55,15 +55,17 @@ function curveBounds(crvPoints::Array{Float64,2}) return bounds end + function chainBounds(chain::Array{Any}) bounds = emptyBounds() for crv in chain crvBounds = curveBounds(crv) bounds = bboxUnion(bounds,crvBounds) - end + end return bounds end + """ bboxUnion(box1::Array{Float64}, box2::Array{Float64}) @@ -78,9 +80,12 @@ function bboxUnion(box1::Array{Float64}, box2::Array{Float64}) return union end + + """ + emptyBounds() -Returns an array that will always be ignored when unioned with +Returns an array that will always be ignored when unioned with another bounding box. """ function emptyBounds() diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 8443dec2..41657438 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -39,6 +39,8 @@ function addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) enableNotifications() postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int} ) @@ -66,6 +68,7 @@ function addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) return nothing end + """ addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) @@ -99,6 +102,7 @@ function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64 return nothing end + """ removeBackgroundGrid!(proj::Project) @@ -112,6 +116,7 @@ function removeBackgroundGrid!(proj::Project) return nothing end + """ setBackgroundGridSpacing!(proj::Project, dx::Float64, dy::Float64, dz::Float64 = 0.0) @@ -142,6 +147,8 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, dz::Flo (oldSpacing[1],oldSpacing[2],0.0),"Set Background Grid Spacing") return nothing end + + """ getBackgroundGridSize(proj::Project) @@ -157,6 +164,8 @@ function getBackgroundGridSize(proj::Project) error("No background grid size is present.") end end + + """ function getBackgroundGridLowerLeft(proj::Project) @@ -170,6 +179,8 @@ function getBackgroundGridLowerLeft(proj::Project) error("No background grid initial point x0 is present.") end end + + """ function getBackgroundGridSteps(proj::Project) @@ -183,6 +194,8 @@ function getBackgroundGridSteps(proj::Project) error("No background grid step size is present.") end end + + """ setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) @@ -204,6 +217,8 @@ function setBackgroundGridLowerLeft!(proj::Project, x0::Array{Float64}) postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing end + + """ setBackgroundGridSteps!(proj::Project, N::Array{Int}) @@ -225,6 +240,8 @@ function setBackgroundGridSteps!(proj::Project, N::Array{Int}) postNotificationWithName(proj,"BGRID_DID_CHANGE_NOTIFICATION",(nothing,)) return nothing end + + """ setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) """ @@ -232,6 +249,8 @@ function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) setBackgroundGridSize!(proj, dx[1], dx[2], key) return nothing end + + """ setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) """ @@ -250,6 +269,7 @@ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::Str return nothing end + """ addBackgroundGrid!(proj::Project, dict::Dict{String,Any}) diff --git a/src/Project/ControlInputAPI.jl b/src/Project/ControlInputAPI.jl index 33ec96e4..8b8a7443 100644 --- a/src/Project/ControlInputAPI.jl +++ b/src/Project/ControlInputAPI.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -35,6 +35,7 @@ function getControlDict(proj::Project) end end + function getDictInControlDictNamed(proj::Project,name::String) controlDict = getControlDict(proj) @@ -48,6 +49,7 @@ function getDictInControlDictNamed(proj::Project,name::String) end end + function getListInControlDictNamed(proj::Project,name::String) dict = getDictInControlDictNamed(proj::Project,name::String) if haskey(dict,"LIST") diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index f92dc19f..1a12f912 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -26,9 +26,9 @@ """ newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0" ) + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0" ) Creates and returns a new parametricEquationCurve in the form of a Dictionary """ @@ -49,6 +49,8 @@ function newParametricEquationCurve(name::String, enableNotifications() return crv end + + """ newEndPointsLineCurve(name::String, xStart::Array{Float64},xEnd::Array[Float64]) @@ -68,6 +70,8 @@ function newEndPointsLineCurve(name::String, enableUndo() return crv end + + """ newCircularArcCurve(name::String, center::Array{Float64}, startAngle::Float64, endAngle::Float64, @@ -96,6 +100,8 @@ function newCircularArcCurve(name::String, enableUndo() return arc end + + """ newSplineCurve(name::String, nKnots::Int, data::Array{Float64,4}) @@ -113,6 +119,8 @@ function newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) enableUndo() return spline end + + """ newSplineCurve(name::String, dataFile::String) @@ -135,6 +143,8 @@ function newSplineCurve(name::String, dataFile::String) end return spline end + + #""" # duplicateCurve(crv::Dict{String,Any}, newName::String) # @@ -151,6 +161,8 @@ end # enableUndo() # return duplicate # end + + """ setCurveName!(curveDict, name) @@ -164,12 +176,16 @@ function setCurveName!(crv::Dict{String,Any}, name::String) end crv["name"] = name end + + """ getCurveName(crv::Dict{String,Any}) """ function getCurveName(crv::Dict{String,Any}) return crv["name"] end + + """ getCurveType(crv::Dic{String,Any}) @@ -179,6 +195,8 @@ end function getCurveType(crv::Dict{String,Any}) return crv["TYPE"] end + + """ setXEqn!(parametricEquationCurve, eqn) @@ -192,6 +210,8 @@ function setXEqn!(crv::Dict{String,Any}, eqn::String) crv["xEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getXEqn(crv::Dict{String,Any}) """ @@ -201,6 +221,8 @@ function getXEqn(crv::Dict{String,Any}) end return nothing end + + """ setYEqn!(parametricEquationCurve, eqn) @@ -214,6 +236,8 @@ function setYEqn!(crv::Dict{String,Any}, eqn::String) crv["yEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getYEqn(crv::Dict{String,Any}) """ @@ -223,6 +247,8 @@ function getYEqn(crv::Dict{String,Any}) end return nothing end + + """ setZEqn!(parametricEquationCurve, eqn) @@ -236,6 +262,8 @@ function setZEqn!(crv::Dict{String,Any}, eqn::String) crv["zEqn"] = eqn postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getZEqn(crv::Dict{String,Any}) """ @@ -245,6 +273,8 @@ function getZEqn(crv::Dict{String,Any}) end return nothing end + + """ setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) @@ -255,6 +285,7 @@ function setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) setStartPoint!(crv,pStr) end + function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xStart" if haskey(crv,key) @@ -264,6 +295,8 @@ function setStartPoint!(crv::Dict{String,Any}, pointAsString::String) crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getStartPoint(crv::Dict{String,Any}, point::Array{Float64}) @@ -272,6 +305,8 @@ Get the start point for a line curve as an array function getStartPoint(crv::Dict{String,Any}) return realArrayForKeyFromDictionary("xStart",crv) end + + """ setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) @@ -282,6 +317,7 @@ function setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) setEndPoint!(crv,pStr) end + function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) key = "xEnd" if haskey(crv,key) @@ -291,6 +327,8 @@ function setEndPoint!(crv::Dict{String,Any}, pointAsString::String) crv[key] = pointAsString postNotificationWithName(crv,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getEndPoint(crv::Dict{String,Any}, point::Array{Float64}) @@ -299,6 +337,8 @@ Get the end point for a line curve as an array. function getEndPoint(crv::Dict{String,Any}) return realArrayForKeyFromDictionary("xEnd",crv) end + + """ setArcUnits(crv::Dict{String,Any}, units::String) @@ -317,6 +357,8 @@ function setArcUnits!(arc::Dict{String,Any}, units::String) println("Units must either be `degrees` or `radians`. Try setting `units` again.") end end + + """ getArcUnits(crv::Dict{String,Any}, units::String) @@ -325,6 +367,8 @@ Get the units for the start and end angles of a circular arc curve. function getArcUnits(arc::Dict{String,Any}) return arc["units"] end + + """ setArcCenter!(crv::Dict{String,Any}, point::Array{Float64}) @@ -344,6 +388,8 @@ function setArcCenter!(arc::Dict{String,Any}, pointAsString::String) arc[key] = pointAsString postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getArcCenter(crv::Dict{String,Any}, point::Array{Float64}) @@ -352,10 +398,11 @@ Get the center of a circular arc as an array function getArcCenter(arc::Dict{String,Any}) return realArrayForKeyFromDictionary("center",arc) end + + """ setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - - """ +""" function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) key = "start angle" if haskey(arc,key) @@ -365,17 +412,19 @@ function setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) arc[key] = string(angle) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getArcStartAngle(arc::Dict{String,Any}, angle::Float64) - - """ +""" function getArcStartAngle(arc::Dict{String,Any}) return parse(Float64,arc["start angle"]) end + + """ setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - - """ +""" function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) key = "end angle" if haskey(arc,key) @@ -385,17 +434,19 @@ function setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) arc[key] = string(angle) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getArcEndAngle(arc::Dict{String,Any}, angle::Float64) - - """ +""" function getArcEndAngle(arc::Dict{String,Any}) return parse(Float64,arc["end angle"]) end + + """ setArcRadius!(arc::Dict{String,Any}, radius::Float64) - - """ +""" function setArcRadius!(arc::Dict{String,Any}, radius::Float64) key = "radius" if haskey(arc,key) @@ -405,6 +456,8 @@ function setArcRadius!(arc::Dict{String,Any}, radius::Float64) arc[key] = string(radius) postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getArcRadius(arc::Dict{String,Any}, radius::Float64) @@ -412,6 +465,8 @@ end function getArcRadius(arc::Dict{String,Any}) return parse(Float64,arc["radius"]) end + + """ setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) """ @@ -424,12 +479,16 @@ function setSplineNKnots!(spline::Dict{String,Any}, nKnots::Int) spline["nKnots"] = string(nKnots) postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getSplineNKnots(spline::Dict{String,Any}) """ function getSplineNKnots(spline::Dict{String,Any}) return parse(Int,spline["nKnots"]) end + + """ setSplinePoints!(spline::Dict{String,Any},points::Array{Float64,4}) """ @@ -441,6 +500,8 @@ function setSplinePoints!(spline::Dict{String,Any},points::Matrix{Float64}) spline["SPLINE_DATA"] = points postNotificationWithName(spline,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ getSplinePoints(spline::Dict{String,Any}) """ diff --git a/src/Project/Generics.jl b/src/Project/Generics.jl index 3aad6af7..b7ce4a96 100644 --- a/src/Project/Generics.jl +++ b/src/Project/Generics.jl @@ -42,6 +42,7 @@ function new(name::String, return newParametricEquationCurve(name, xEqn, yEqn, zEqn) end + """ new(name::String, xStart::Array{Float64}, @@ -55,6 +56,7 @@ function new(name::String, return newEndPointsLineCurve(name, xStart, xEnd) end + """ new(name::String, center::Array{Float64}, @@ -74,6 +76,7 @@ function new(name::String, return newCircularArcCurve(name,center,radius,startAngle,endAngle,units) end + """ new(name::String, dataFile::String) @@ -83,6 +86,7 @@ function new(name::String, dataFile::String) return newSplineCurve(name, dataFile) end + """ new(name::String, nKnots::Int, data::Matrix{Float64}) @@ -91,6 +95,8 @@ Create a spline curve from an array of knots function new(name::String, nKnots::Int, data::Matrix{Float64}) return newSplineCurve(name, nKnots, data) end + + # # Adding curves to a model # @@ -108,6 +114,7 @@ function add!(proj::Project, obj::Dict{String,Any}) end end + """ add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @@ -117,6 +124,7 @@ function add!(proj::Project, crv::Dict{String,Any}, boundaryName::String) addCurveToInnerBoundary!(proj, crv, boundaryName) end + """ getCurve(proj::Project, curveName::String) @@ -126,6 +134,7 @@ function getCurve(proj::Project, curveName::String) return getOuterBoundaryCurveWithName(proj, curveName) end + """ getCurve(proj::Project, curveName::String, boundaryName::String) @@ -135,6 +144,7 @@ function getCurve(proj::Project, curveName::String, boundaryName::String) return getInnerBoundaryCurve(proj, curveName, boundaryName) end + """ getInnerBoundary(proj::Project, name::String) @@ -144,6 +154,7 @@ function getInnerBoundary(proj::Project, name::String) return getInnerBoundaryChainWithName(proj, name) end + """ remove!(proj::Project, curveName::String) @@ -153,6 +164,7 @@ function remove!(proj::Project, curveName::String) removeOuterBoundaryCurveWithName!(proj, curveName) end + """ remove!(proj::Project, curveName::String, innerBoundaryName::String) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 80eb6789..fc923bc8 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -106,6 +106,7 @@ function insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + """ removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) @@ -121,6 +122,8 @@ function removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) registerWithUndoManager(proj,insertOuterBoundaryCurveAtIndex!,(crv,indx),"Remove Outer Boundary Curve") postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + + """ addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) @@ -187,6 +190,7 @@ function getOuterBoundaryChainList(proj::Project) end end + # # -------------------------------------------------------------------------------------- # INNER BOUNDARY FUNCTIONS diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 7c1fd392..d015e6d4 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -23,6 +23,7 @@ --- End License =# + #= The Project is the controller in an MVC paradigm. It manages the model, stored in the projectDictionary, and plotting data, and responds to enableNotifications @@ -62,6 +63,7 @@ const smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) const statusValues = Set(["ON", "OFF"]) const refinementTypes = Set(["smooth", "sharp"]) + """ openProject(fileName::String, folder::String) @@ -94,6 +96,8 @@ function openProject(fileName::String, folder::String) return proj end + + """ saveProject(proj::Project) @@ -104,6 +108,8 @@ function saveProject(proj::Project) fileName = joinpath(proj.projectDirectory,proj.name)*".control" WriteControlFile(proj.projectDictionary,fileName) end + + """ newProject(name::String, folder::String) @@ -153,6 +159,8 @@ function newProject(name::String, folder::String) enableUndo() return proj end + + """ hasBackgroundGrid(proj::Project) @@ -167,6 +175,7 @@ function hasBackgroundGrid(proj::Project) end end + function assemblePlotArrays(proj::Project) empty!(proj.outerBndryPoints) @@ -224,6 +233,7 @@ function assemblePlotArrays(proj::Project) proj.bounds = bounds end + function projectBounds(proj::Project) bounds = emptyBounds() @@ -242,6 +252,7 @@ function projectBounds(proj::Project) return bounds end + function projectGrid(proj::Project) controlDict = proj.projectDictionary["CONTROL_INPUT"] @@ -287,6 +298,8 @@ function projectGrid(proj::Project) return xGrid, yGrid end + + # # NOTIFICATION ACTIONS # @@ -323,6 +336,7 @@ function curveDidChange(proj::Project,crv::Dict{String,Any}) return nothing end + function modelDidChange(proj::Project, sender::Project) if proj === sender && !isnothing(proj.plt) @@ -334,6 +348,7 @@ function modelDidChange(proj::Project, sender::Project) end end + function backgroundGridDidChange(proj::Project, sender::Project) if proj === sender && !isnothing(proj.plt) proj.backgroundGridShouldUpdate = true @@ -345,6 +360,7 @@ function backgroundGridDidChange(proj::Project, sender::Project) end end + function refinementWasAdded(proj::Project, sender::Project) if proj === sender && !isnothing(proj.plt) options = proj.plotOptions @@ -355,6 +371,7 @@ function refinementWasAdded(proj::Project, sender::Project) end end + function refinementDidChange(proj::Project, sender::Dict{String,Any}) regionName = sender["name"] lst = getAllRefinementRegions(proj) @@ -387,6 +404,7 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) end end + function meshWasGenerated(proj::Project, sender::Project) if proj === sender && !isnothing(proj.plt) options = proj.plotOptions @@ -396,6 +414,7 @@ function meshWasGenerated(proj::Project, sender::Project) end end + function meshWasDeleted(proj::Project, sender::Project) if proj === sender && !isnothing(proj.plt) options = proj.plotOptions diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index ed9f8e2d..3da0d6cf 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -25,16 +25,16 @@ =# """ -newRefinementCenter(type, - center, meshSize, - width ) + newRefinementCenter(name, type, + center, meshSize, + width) Create refinement center of `type` "smooth" or "sharp" centered at `center = [x,y,z]`` with a mesh size `meshSize` spread over a radius `width`. """ function newRefinementCenter(name::String, type::String, x0::Array{Float64}, h::Float64, - w::Float64 ) + w::Float64) disableUndo() disableNotifications() centerDict = Dict{String,Any}() @@ -48,6 +48,8 @@ function newRefinementCenter(name::String, type::String, enableUndo() return centerDict end + + """ addRefinementRegion!(proj::Project,r::Dict{String,Any}) @@ -62,6 +64,8 @@ function addRefinementRegion!(proj::Project,r::Dict{String,Any}) enableNotifications() postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) end + + """ addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) @@ -75,10 +79,12 @@ function addRefinementRegionPoints!(proj::Project, r::Dict{String,Any}) center = getRefinementRegionCenter(r) push!(proj.refinementRegionLoc,center) end + + """ refinementRegionPoints(r::Dict{String,Any}) - Returns Array{Float64,2} being the plotting points of a refinement region +Returns Array{Float64,2} being the plotting points of a refinement region """ function refinementRegionPoints(r::Dict{String,Any}) @@ -116,6 +122,8 @@ function refinementRegionPoints(r::Dict{String,Any}) end end + + """ getRefinementRegionCenter(r::Dict{String,Any}) @@ -132,6 +140,8 @@ function getRefinementRegionCenter(r::Dict{String,Any}) return xAvg[1:2] end end + + """ removeRefinementRegion!(proj::Project, name::String) @@ -148,6 +158,8 @@ function removeRefinementRegion!(proj::Project, name::String) enableNotifications() postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) end + + """ insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) @@ -164,14 +176,13 @@ function insertRefinementRegion!(proj::Project, r::Dict{String,Any}, indx::Int) insert!(proj.refinementRegionNames,indx,r["name"]) postNotificationWithName(proj,"REFINEMENT_WAS_ADDED_NOTIFICATION",(nothing,)) end -# -# -------------------------------------------------------------------------------------- -# + + """ - newRefinementLine(type, - start, end, - meshSize, - width ) + newRefinementLine(name, type, + start, end, + meshSize, + width) Create refinement line of type "smooth" or "sharp" between `start` = [x,y,z] and `end` = [x,y,z] with a mesh size `meshSize` spread over a width `width`. @@ -179,7 +190,7 @@ with a mesh size `meshSize` spread over a width `width`. function newRefinementLine(name::String, type::String, x0::Array{Float64}, x1::Array{Float64}, h::Float64, - w::Float64 ) + w::Float64) disableUndo() disableNotifications() lineDict = Dict{String,Any}() @@ -194,9 +205,8 @@ function newRefinementLine(name::String, type::String, enableUndo() return lineDict end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementRegion(proj::Project, indx) @@ -210,9 +220,8 @@ function getRefinementRegion(proj::Project, indx::Int) end return lst[indx] end -# -# -------------------------------------------------------------------------------------- -# + + """ getAllRefinementRegions(proj::Project) @@ -222,9 +231,8 @@ function getAllRefinementRegions(proj::Project) lst = getListInControlDictNamed(proj,"REFINEMENT_REGIONS") return lst end -# -# -------------------------------------------------------------------------------------- -# + + """ (i,r) = getRefinementRegion(project, name) @@ -239,9 +247,8 @@ function getRefinementRegion(proj::Project, name::String) end error("Refinement region with name ", name, " not found!") end -# -# -------------------------------------------------------------------------------------- -# + + """ setRefinementType!(refinementRegion, type) @@ -259,9 +266,8 @@ function setRefinementType!(r::Dict{String,Any}, type::String) end r["type"] = type end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementType(r::Dict{String,Any}) @@ -271,11 +277,13 @@ represents the refinement region. function getRefinementType(r::Dict{String,Any}) return r["type"] end + + """ setRefinementName!(r::Dict{String,Any}, type) Set a name for the refinement region.`r` is the dictionary that - represents the refinement region. +represents the refinement region. """ function setRefinementName!(r::Dict{String,Any}, name::String) if haskey(r,"name") @@ -285,20 +293,18 @@ function setRefinementName!(r::Dict{String,Any}, name::String) r["name"] = name postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementName(r::Dict{String,Any}) -Return name of the refinement. `r` is the dictionary that -represents the refinement region. +Return name of the refinement. `r` is the dictionary that represents the refinement region. """ function getRefinementName(r::Dict{String,Any}) return r["name"] -end# -# -------------------------------------------------------------------------------------- -# +end + + """ setRefinementLocation!(refinementCenter, location) @@ -310,6 +316,7 @@ function setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) return nothing end + function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x0") old = r["x0"] @@ -319,9 +326,8 @@ function setRefinementLocation!(r::Dict{String,Any}, x0Str::String) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) return nothing end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementLocation(r::Dict{String,Any}) @@ -331,9 +337,8 @@ represents the refinement region. function getRefinementLocation(r::Dict{String,Any}) return realArrayForKeyFromDictionary("x0",r) end -# -# -------------------------------------------------------------------------------------- -# + + """ setRefinementGridSize!(r::Dict{String,Any}, h) @@ -349,13 +354,13 @@ function setRefinementGridSize!(r::Dict{String,Any}, h::Float64) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end + function setRefinementGridSize!(r::Dict{String,Any}, h::String) hf = parse(Float64,h) setRefinementGridSize!(r,hf) end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementGridSize(r::Dict{String,Any}) @@ -365,9 +370,8 @@ represents the refinement region. function getRefinementGridSize(r::Dict{String,Any}) return parse(Float64,r["h"]) end -# -# -------------------------------------------------------------------------------------- -# + + """ setRefinementWidth!(r::Dict{String,Any}, width) @@ -383,6 +387,7 @@ function setRefinementWidth!(r::Dict{String,Any},w::Float64) postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end + function setRefinementWidth!(r::Dict{String,Any},w::String) wf = parse(Float64,w) setRefinementWidth!(r,wf) @@ -399,9 +404,8 @@ represents the refinement region. function getRefinementWidth(r::Dict{String,Any}) return parse(Float64,r["w"]) end -# -# -------------------------------------------------------------------------------------- -# + + """ setRefinementStart!(refinementRegion, location) @@ -412,6 +416,7 @@ function setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) setRefinementStart!(r,x0Str) end + function setRefinementStart!(r::Dict{String,Any}, x0Str::String) if haskey(r,"x0") old = r["x0"] @@ -420,9 +425,8 @@ function setRefinementStart!(r::Dict{String,Any}, x0Str::String) r["x0"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementStart (r::Dict{String,Any}) @@ -432,9 +436,8 @@ represents the refinement region. function getRefinementStart(r::Dict{String,Any}) return realArrayForKeyFromDictionary("x0",r) end -# -# -------------------------------------------------------------------------------------- -# + + """ setRefinementEnd!(refinementRegion, location) @@ -453,9 +456,8 @@ function setRefinementEnd!(r::Dict{String,Any}, x0Str::String) r["x1"] = x0Str postNotificationWithName(r,"REFINEMENT_WAS_CHANGED_NOTIFICATION",(nothing,)) end -# -# -------------------------------------------------------------------------------------- -# + + """ getRefinementEnd(r::Dict{String,Any}) diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index 3f83e7bf..beb9556e 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -47,6 +47,8 @@ function addRunParameters!(proj::Project, return rpDict end + + """ removeRunParameters!(proj::Project) @@ -59,6 +61,7 @@ function removeRunParameters!(proj::Project) end end + """ setName(proj::Project,name::String) @@ -72,6 +75,8 @@ function setName!(proj::Project,name::String) proj.name = name setFileNames!(proj, getMeshFileFormat(proj)) end + + """ getName(proj::Project) @@ -81,6 +86,8 @@ stats files. function getName(proj::Project) return proj.name end + + """ setPolynomialOrder(proj::Project, p::Int) @@ -95,6 +102,8 @@ function setPolynomialOrder!(proj::Project, p::Int) end rpDict["polynomial order"] = string(p) end + + """ getPolynomialOrder(proj::Project) @@ -104,6 +113,8 @@ function getPolynomialOrder(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return parse(Int,rpDict["polynomial order"]) end + + """ setMeshFileFormat(proj::Project, meshFileFormat::String) @@ -123,6 +134,8 @@ function setMeshFileFormat!(proj::Project, meshFileFormat::String) end rpDict[key] = meshFileFormat end + + """ getMeshFileFormat(proj::Project) @@ -132,6 +145,8 @@ function getMeshFileFormat(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["mesh file format"] end + + """ setPlotFileFormat(proj::Project, plotFileFormat::String) @@ -152,6 +167,8 @@ function setPlotFileFormat!(proj::Project, plotFileFormat::String) end rpDict[key] = plotFileFormat end + + """ getPlotFileFormat(proj::Project) @@ -162,6 +179,7 @@ function getPlotFileFormat(proj::Project) return rpDict["plot file format"] end + function setFileNames!(proj::Project, meshFileFormat::String) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") if meshFileFormat == "ABAQUS" @@ -173,16 +191,19 @@ function setFileNames!(proj::Project, meshFileFormat::String) rpDict["stats file name"] = joinpath(proj.projectDirectory, proj.name *".txt") end + function getMeshFileName(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["mesh file name"] end + function getPlotFileName(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["plot file name"] end + function getStatsFileName(proj::Project) rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") return rpDict["stats file name"] diff --git a/src/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl index 87a49631..9d508f17 100644 --- a/src/Project/SmootherAPI.jl +++ b/src/Project/SmootherAPI.jl @@ -3,36 +3,35 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# """ addSpringSmoother!(status::String, type::String, nIterations::Int) - status is either `ON` or `OFF` - type is either `LinearSpring` or `LinearAndCrossbarSpring` - +Status is either `ON` or `OFF` +Type is either `LinearSpring` or `LinearAndCrossbarSpring` """ -function addSpringSmoother!(proj::Project,status::String = "ON", - type::String = "LinearAndCrossbarSpring", +function addSpringSmoother!(proj::Project,status::String = "ON", + type::String = "LinearAndCrossbarSpring", nIterations::Int = 25) if !in(status,statusValues) println("Acceptable smoother status are: ", statusValues,". Try again.") @@ -46,10 +45,12 @@ function addSpringSmoother!(proj::Project,status::String = "ON", setSmoothingType!(proj,type) setSmoothingIterations!(proj,nIterations) end + + """ setSmoothingStatus(proj:Project, status::String) -status is either "ON" or "OFF" +Status is either "ON" or "OFF" """ function setSmoothingStatus!(proj::Project, status::String) if !in(status,statusValues) @@ -59,6 +60,8 @@ function setSmoothingStatus!(proj::Project, status::String) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") smDict["smoothing"] = status end + + """ smoothingStatus(proj::Project) @@ -68,10 +71,12 @@ function getSmoothingStatus(proj::Project) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") return smDict["smoothing"] end + + """ -setSmoothingType!(proj:Project, status::String) + setSmoothingType!(proj:Project, status::String) -type is either `LinearSpring` or `LinearAndCrossbarSpring` +Type is either `LinearSpring` or `LinearAndCrossbarSpring` """ function setSmoothingType!(proj::Project, type::String) if !in(type,smootherTypes) @@ -81,6 +86,8 @@ function setSmoothingType!(proj::Project, type::String) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") smDict["smoothing type"] = type end + + """ getSmoothingType(proj::Project) @@ -90,6 +97,8 @@ function getSmoothingType(proj::Project) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") return smDict["smoothing type"] end + + """ setSmoothingIterations!(proj::Project, iterations::Int) @@ -99,6 +108,8 @@ function setSmoothingIterations!(proj::Project, iterations::Int) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") smDict["number of iterations"] = iterations end + + """ getSmoothingIterations(proj::Project) @@ -108,6 +119,8 @@ function getSmoothingIterations(proj::Project) smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") return smDict["number of iterations"] end + + """ removeSpringSmoother!(proj::Project) diff --git a/src/Project/Undo.jl b/src/Project/Undo.jl index c14438f3..482d00bd 100644 --- a/src/Project/Undo.jl +++ b/src/Project/Undo.jl @@ -3,24 +3,24 @@ Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in all + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - + --- End License =# @@ -29,7 +29,7 @@ struct UROperation action::Any data ::Tuple name ::String -end +end @enum UNDO_OPERATION_TYPE begin UNDO_USER_OPERATION = 0 @@ -45,13 +45,14 @@ property of the project would replace HQMglobalUndoStack. This is not a big deal except if multiple projects are open, and muliple objects like curves have been defined but not added to a project. In interactive mode curves are separate from projects until added. (The same curve could be added to multiple projects.) So some logic needs to be -figured out before modifying below. If only one project is managed per session, +figured out before modifying below. If only one project is managed per session, then this is not a problem. =# HQMglobalUndoStack = [] HQMglobalRedoStack = [] HQMglobalChangeOP = UNDO_IGNORE + function undo() if !isempty(HQMglobalUndoStack) op = pop!(HQMglobalUndoStack) @@ -70,6 +71,7 @@ function undo() return "Empty undo stack. No action performed." end + function redo() if !isempty(HQMglobalRedoStack) op = pop!(HQMglobalRedoStack) @@ -88,11 +90,13 @@ function redo() return "Empty redo stack. No action performed." end + function registerUndo(obj, action, data::Tuple, name::String) uOp = UROperation(obj,action,data,name) push!(HQMglobalUndoStack,uOp) end + function registerWithUndoManager(obj, action, oldData::Tuple, name::String) if HQMglobalChangeOP == UNDO_USER_OPERATION #User action @@ -111,11 +115,13 @@ function registerRedo(obj, action, data::Tuple, name::String) push!(HQMglobalRedoStack,rOp) end + function clearUndoRedo() empty!(HQMglobalUndoStack) empty!(HQMglobalRedoStack) end + function undoActionName() if !isempty(HQMglobalUndoStack) op = last(HQMglobalUndoStack) @@ -133,10 +139,12 @@ function redoActionName() return "No redo action in queue" end + function disableUndo() global HQMglobalChangeOP = UNDO_IGNORE end + function enableUndo() global HQMglobalChangeOP = UNDO_USER_OPERATION end diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index de0d6b4f..f629a777 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -226,6 +226,7 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS end end + function plotMesh(plt, xMesh::Array{Float64}, yMesh::Array{Float64}) lines!(plt[1,1], xMesh,yMesh) end diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index 751e9e51..a987acca 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -26,6 +26,8 @@ const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 const REFINEMENTS = 8; const ALL = 15 + + """ plotProject!(proj::Project, plotOptions::Int = 0) @@ -94,7 +96,7 @@ function plotProject!(proj::Project, plotOptions::Int = 0) plotNumbers = ["O."*string(i) for i in 1:length(proj.outerBndryNames)] plotNames = String[] for j = 1:length(proj.outerBndryNames) - push!(plotNames, plotNumbers[j]*"| Outer."*proj.outerBndryNames[j] ) + push!(plotNames, plotNumbers[j]*"| Outer."*proj.outerBndryNames[j] ) end plotChain!(plt,proj.outerBndryPoints, plotNames, plotNumbers) end @@ -108,7 +110,7 @@ function plotProject!(proj::Project, plotOptions::Int = 0) plotNumbers = [string(i)*"."*string(j) for j in 1:length(innerBndryNames)] plotNames = String[] for j = 1:length(innerBndryNames) - push!(plotNames, plotNumbers[j]*"| "*innerBndryNames[j] ) + push!(plotNames, plotNumbers[j]*"| "*innerBndryNames[j] ) end plotChain!(plt,innerBndryPts, plotNames, plotNumbers) end @@ -134,6 +136,8 @@ function plotProject!(proj::Project, plotOptions::Int = 0) ax.aspect = DataAspect() display(plt) end + + """ updatePlot!(proj::Project) @@ -146,14 +150,16 @@ function updatePlot!(proj::Project) plotProject!(proj, plotOptions) end end + + """ -updatePlot!(proj::Project, plotOptions::Int) + updatePlot!(proj::Project, plotOptions::Int) Replot with the new plotOptions = combinations (sums) of GRID, MESH, MODEL, REFINEMENTS -Example: updatePlot(p, MESH + MODEL) +Example: updatePlot!(p, MESH + MODEL) """ function updatePlot!(proj::Project, plotOptions::Int) if !isnothing(proj.plt) @@ -162,6 +168,7 @@ function updatePlot!(proj::Project, plotOptions::Int) end end + function plotChain!(plt, chainPoints::Array{Any}, legendLabels::Array{String}, curveLabels::Array{String} ) x = chainPoints[1] plotCurve(plt, x, legendLabels[1], curveLabels[1]) @@ -171,15 +178,16 @@ function plotChain!(plt, chainPoints::Array{Any}, legendLabels::Array{String}, c for i = 2:s x = chainPoints[i] plotCurve(plt,x,legendLabels[i], curveLabels[i]) - end + end end + function plotCurve(plt, points::Matrix{Float64}, legendLabel::String, curveLabel::String) lines!(plt[1,1],points[:,1],points[:,2], label = legendLabel, linewidth = 5 ) s = size(points) np = div(s[1], 2, RoundNearest) if s[1] == 3 - np = 2 + np = 2 end # dx = points[np+1,1] - points[np-1,1] # dy = points[np+1,2] - points[np-1,2] @@ -191,6 +199,7 @@ function plotCurve(plt, points::Matrix{Float64}, legendLabel::String, curveLabel text!(plt[1,1],curveLabel,textsize = 28, position = pp, align = (:center,:center) ) end + function plotRefinement(plt, points::Array{Matrix{Float64}}, label::Array{String}, loc::Array{Array{Float64}}) for (i,reg) in enumerate(points) From 652df2cb7e42186e55f15c03c484495fdf9e5b5c Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 15:09:01 +0200 Subject: [PATCH 123/164] add proper warnings for undefined status types or unjoined curves --- src/HOHQMesh.jl | 2 +- src/Mesh/Meshing.jl | 2 +- src/Project/CurvesAPI.jl | 2 +- src/Project/ModelAPI.jl | 6 +++--- src/Project/RefinementRegionsAPI.jl | 2 +- src/Project/RunParametersAPI.jl | 4 ++-- src/Project/SmootherAPI.jl | 8 ++++---- test/test_curve.jl | 4 ++-- test/test_model.jl | 10 +++++----- test/test_refinement.jl | 2 +- test/test_run_parameters.jl | 4 ++-- test/test_smoother.jl | 8 ++++---- test/test_visualization.jl | 9 +++++---- 13 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index ea1c10ba..782eba97 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -306,7 +306,7 @@ examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") # # Include functionality for interactive reading and writing a model for HOHQMesh -# Note, The visualzation routines are included above in the `__init__` above because +# Note, The visualzation routines are included above in the `__init__` because # Makie is required # diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 6e0b83bf..2e572ae6 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -30,7 +30,7 @@ function generate_mesh(proj::Project) # controlDict = getControlDict(proj) if !haskey(controlDict,"BACKGROUND_GRID") - println("A background grid is needed before meshing. Add one and try again.") + @warn "A background grid is needed before meshing. Add one and try again." return nothing end saveProject(proj) diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 1a12f912..741233e6 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -354,7 +354,7 @@ function setArcUnits!(arc::Dict{String,Any}, units::String) arc[key] = units postNotificationWithName(arc,"CURVE_DID_CHANGE_NOTIFICATION",(nothing,)) else - println("Units must either be `degrees` or `radians`. Try setting `units` again.") + @warn "Units must either be `degrees` or `radians`. Try setting `units` again." end end diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index fc923bc8..04fd9b88 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -44,7 +44,7 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) if !curvesMeet(lastCurve,crv) lastName = getCurveName(lastCurve) newName = getCurveName(crv) - println("the curve $lastName does not meet the previous curve, $newName. Try again.") + @warn "The curve $lastName does not meet the previous curve, $newName. Try again." return end end @@ -214,7 +214,7 @@ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundary if !curvesMeet(lastCurve,crv) lastName = getCurveName(lastCurve) newName = getCurveName(crv) - println("the curve $lastName does not meet the previous curve, $newName. Try again.") + @warn "The curve $lastName does not meet the previous curve, $newName. Try again." return end end @@ -442,7 +442,7 @@ function getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::S return crv end end - println("No curve ", curveName, " in boundary ", boundaryName, ". Try again.") + @warn "No curve "*curveName*" in boundary "*boundaryName*". Try again." return nothing end diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 3da0d6cf..800b230a 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -256,7 +256,7 @@ Set the type, either "smooth" or "sharp" for the given refinement region. """ function setRefinementType!(r::Dict{String,Any}, type::String) if !in(type,refinementTypes) - println("Acceptable refinement types are `smooth` and `sharp`. Try again.") + @warn "Acceptable refinement types are `smooth` and `sharp`. Try again." return end diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index beb9556e..ea708cd2 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -123,7 +123,7 @@ are "ISM", "ISM-V2", or "ABAQUS". """ function setMeshFileFormat!(proj::Project, meshFileFormat::String) if !in(meshFileFormat,meshFileFormats) - println("Acceptable file formats are: ", meshFileFormats,". Try again.") #TODO Format this nicely + @warn "Acceptable file formats are: `ISM-V2`, `ISM`, or `ABAQUS`. Try again." return end key = "mesh file format" @@ -156,7 +156,7 @@ only the corner nodes. """ function setPlotFileFormat!(proj::Project, plotFileFormat::String) if !in(plotFileFormat,plotFileFormats) - println("Acceptable plot formats are: ", plotFileFormats,". Try again.") #TODO Format this nicely + @warn "Acceptable plot formats are: `sem` or `skeleton`. Try again." return end rpDict = getDictInControlDictNamed(proj,"RUN_PARAMETERS") diff --git a/src/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl index 9d508f17..5da4c2cb 100644 --- a/src/Project/SmootherAPI.jl +++ b/src/Project/SmootherAPI.jl @@ -34,11 +34,11 @@ function addSpringSmoother!(proj::Project,status::String = "ON", type::String = "LinearAndCrossbarSpring", nIterations::Int = 25) if !in(status,statusValues) - println("Acceptable smoother status are: ", statusValues,". Try again.") + @warn "Acceptable smoother status are: `ON` or `OFF`. Try again." return end if !in(type,smootherTypes) - println("Acceptable smoothers are:", smootherTypes, ". Try again.") + @warn "Acceptable smoothers are: `LinearAndCrossbarSpring` or `LinearSpring`. Try again." return end setSmoothingStatus!(proj,status) @@ -54,7 +54,7 @@ Status is either "ON" or "OFF" """ function setSmoothingStatus!(proj::Project, status::String) if !in(status,statusValues) - println("Acceptable smoother status is one of: ", statusValues,". Try again.") + @warn "Acceptable smoother status is either: `ON` or `OFF`. Try again." return end smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") @@ -80,7 +80,7 @@ Type is either `LinearSpring` or `LinearAndCrossbarSpring` """ function setSmoothingType!(proj::Project, type::String) if !in(type,smootherTypes) - println("Acceptable smoothers are:", smootherTypes, ". Try again.") + @warn "Acceptable smoothers are: `LinearAndCrossbarSpring` or `LinearSpring`. Try again." return end smDict = getDictInControlDictNamed(proj,"SPRING_SMOOTHER") diff --git a/test/test_curve.jl b/test/test_curve.jl index fa97f584..10c81381 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -147,8 +147,8 @@ using Test @test isapprox(pts[2,:],[0.0,2.0]) @test isapprox(pts[3,:],[-2.0,0.0]) - # purposly trigger warning with invalid units - setArcUnits!(crv,"Rankine") + # Purposly trigger warning with invalid units + @test_logs (:warn, "Units must either be `degrees` or `radians`. Try setting `units` again.") setArcUnits!(crv,"Rankine") setArcUnits!(crv,"radians") @test getArcUnits(crv) == "radians" diff --git a/test/test_model.jl b/test/test_model.jl index 202c1903..c55fc9fa 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -107,22 +107,22 @@ using Test @test getCurveName(ibc) == "obc2" # -# Purposely create outer / inner boundary curves that do -# not join in a new project. This will trigger warning statements. +# Purposely create outer / inner boundary curves that do not join in a new project. +# Triggers appropriate warning statements. # obc1 = new("obc1",[0.0,0.0,0.0], [2.0,0.0,0.0]) obc2 = new("obc2",[3.0,0.0,0.0], [1.0,1.0,0.0]) # Failing outer boundary add!(p, obc1) - add!(p, obc2) + @test_logs (:warn, "The curve obc1 does not meet the previous curve, obc2. Try again.") add!(p, obc2) # Failing inner boundary line = newEndPointsLineCurve("line", [0.0,-2.0,0.0], [1.0,0.0,0.0]) halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.5, 0.0, 180.0, "degrees") - add!(p, line, "failCurve") - addCurveToInnerBoundary!(p, halfCircle , "failCurve") + addCurveToInnerBoundary!(p, line, "failCurve") + @test_logs (:warn, "The curve line does not meet the previous curve, halfCircle. Try again.") add!(p, halfCircle , "failCurve") end diff --git a/test/test_refinement.jl b/test/test_refinement.jl index 0c0ea28c..8954a686 100644 --- a/test/test_refinement.jl +++ b/test/test_refinement.jl @@ -155,7 +155,7 @@ using Test c2 = newRefinementCenter("middle","smooth",[2.0,3.0,4.0],0.6,3.0) # Attempt to set an refinement type. Simply throws a warning to "Try again" - setRefinementType!(c2, "fancy") + @test_logs (:warn, "Acceptable refinement types are `smooth` and `sharp`. Try again.") setRefinementType!(c2, "fancy") insertRefinementRegion!(p,c2,2) lst = getAllRefinementRegions(p) diff --git a/test/test_run_parameters.jl b/test/test_run_parameters.jl index 302a39fc..84cba97b 100644 --- a/test/test_run_parameters.jl +++ b/test/test_run_parameters.jl @@ -68,7 +68,7 @@ using Test redo() @test getMeshFileFormat(p) == "ISM" - setMeshFileFormat!(p,"BLORP") + @test_logs (:warn, "Acceptable file formats are: `ISM-V2`, `ISM`, or `ABAQUS`. Try again.") setMeshFileFormat!(p,"BLORP") @test getMeshFileFormat(p) == "ISM" @test getPlotFileFormat(p) == "skeleton" @@ -79,7 +79,7 @@ using Test redo() @test getPlotFileFormat(p) == "sem" - setPlotFileFormat!(p,"BLORP") + @test_logs (:warn, "Acceptable plot formats are: `sem` or `skeleton`. Try again.") setPlotFileFormat!(p,"BLORP") @test getPlotFileFormat(p) == "sem" removeRunParameters!(p) diff --git a/test/test_smoother.jl b/test/test_smoother.jl index 007a9b0a..deda0076 100644 --- a/test/test_smoother.jl +++ b/test/test_smoother.jl @@ -28,8 +28,8 @@ using Test q = openProject( projectName*".control", projectPath ) # Trigger error statements by setting incorrect values in the smoother options - addSpringSmoother!(p, "PAUSE", "LinearSpring", 50) - addSpringSmoother!(p, "ON" , "MagicSprings", 50) + @test_logs (:warn, "Acceptable smoother status are: `ON` or `OFF`. Try again.") addSpringSmoother!(p, "PAUSE", "LinearSpring", 50) + @test_logs (:warn, "Acceptable smoothers are: `LinearAndCrossbarSpring` or `LinearSpring`. Try again.") addSpringSmoother!(p, "ON" , "MagicSprings", 50) setSmoothingIterations!(q, 25) @@ -41,14 +41,14 @@ using Test @test getSmoothingStatus(q) == "OFF" # Trigger error statement by setting an invalid spring status - setSmoothingStatus!(q,"UNKNOWN") + @test_logs (:warn, "Acceptable smoother status is either: `ON` or `OFF`. Try again.") setSmoothingStatus!(q,"UNKNOWN") @test getSmoothingStatus(q) == "OFF" setSmoothingType!(q,"LinearSpring") @test getSmoothingType(q) == "LinearSpring" # Trigger error statement by setting an invalid spring type - setSmoothingType!(q,"TorsionalSpring") + @test_logs (:warn, "Acceptable smoothers are: `LinearAndCrossbarSpring` or `LinearSpring`. Try again.") setSmoothingType!(q,"TorsionalSpring") @test getSmoothingType(q) == "LinearSpring" cDict = getControlDict(q) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index edb706a0..47734037 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -38,8 +38,8 @@ using CairoMakie tup = getInnerBoundary(p_visu, "inner1") @test tup[2]["TYPE"] == "CHAIN" - # Attempt to generate the mesh before the background grid is set. Throws an error. - @test_nowarn generate_mesh(p_visu) + # Attempt to generate the mesh before the background grid is set. Throws a warning. + @test_logs (:warn, "A background grid is needed before meshing. Add one and try again.") generate_mesh(p_visu) # There is no background grid. Query the different styles of background grids # to test that errors are thrown correctly. @@ -72,11 +72,12 @@ using CairoMakie [1.0 1.75 -1.0 0.0] ] spline2 = new("small_spline", 5, data) add!(p_visu, spline2, "inner2") + # - # Test getting the inner curve and test + # Test getting the inner curve # # Purposely get the names wrong to throw a warning - dict = getCurve(p_visu, "small_spline", "inner1") + @test_logs (:warn, "No curve small_spline in boundary inner1. Try again.") dict = getCurve(p_visu, "small_spline", "inner1") # Do it correctly this time dict = getCurve(p_visu, "small_spline", "inner2") @test dict["TYPE"] == "SPLINE_CURVE" From a3b49433201418f67d1001cdbc64c154c081ea05 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 8 Apr 2022 20:33:28 +0200 Subject: [PATCH 124/164] int types change --- src/ControlFile/ControlFileOperations.jl | 2 +- src/HOHQMesh.jl | 5 ++-- src/Misc/DictionaryOperations.jl | 4 +-- src/Viz/VizMesh.jl | 34 ++++++++++++------------ 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index 651e0cab..b71da7f5 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -297,7 +297,7 @@ function ImportSplineData( splineDict::Dict{String,Any}, f::IOStream) end knotString = splineDict["nKnots"] - nKnots = parse(Int, knotString) + nKnots = parse(Int64, knotString) splineDataArray = zeros(Float64, nKnots, 4) for i = 1:nKnots currentLine = split(readline(f)) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 782eba97..c5693fa2 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -33,8 +33,7 @@ export new, remove! # -# TODO: Go through and cleanup this exporting. Most of this will only be -# exported for automatic testing purposes +# TODO: Go through and cleanup this exporting. # # Functions from `BackgroundGridAPI.jl` export addBackgroundGrid!, @@ -108,7 +107,7 @@ export addCurveToOuterBoundary!, getModelDict, getDictInModelDictNamed -# Functions from `Project.jl` (this is main object of HQMTool) +# Functions from `Project.jl` export openProject, saveProject, newProject, diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index ae3e5863..f66a64e3 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -38,7 +38,7 @@ end function intForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] - return parse(Int,v) + return parse(Int64,v) end @@ -61,7 +61,7 @@ function intArrayForKeyFromDictionary(key::AbstractString, d::Dict{String,Any}) v = d[key] values = match(arrayRegex,v) s = split(values.match,",") - array = [parse(Int,s[1]),parse(Int,s[2]),parse(Int,s[3])] + array = [parse(Int64,s[1]),parse(Int64,s[2]),parse(Int64,s[3])] return array end diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index f629a777..4b3d3a4c 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -32,8 +32,8 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS line = readline(f) # Numbers of nodes, edges ... values = split(line) - nNodes = parse(Int, values[1]) - nEdges = parse(Int, values[2]) + nNodes = parse(Int64, values[1]) + nEdges = parse(Int64, values[2]) # # Read the nodes # @@ -53,8 +53,8 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS for i = 1:3:3*nEdges values = split(readline(f)) - n = parse(Int,values[1]) - m = parse(Int,values[2]) + n = parse(Int64,values[1]) + m = parse(Int64,values[2]) xMesh[i] = nodes[n,1] xMesh[i+1] = nodes[m,1] @@ -73,9 +73,9 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS line = readline(f) # Numbers of corners, elements and boundary polynomial order values = split(line) - nNodes = parse(Int, values[1]) - nElements = parse(Int, values[2]) - nBndy = parse(Int, values[3]) + nNodes = parse(Int64, values[1]) + nElements = parse(Int64, values[2]) + nBndy = parse(Int64, values[3]) # # Read the nodes # @@ -89,16 +89,16 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # # Read the element ids (and skip all the boundary information) # - elements = zeros(Int,nElements,4) - temp = zeros(Int, 4) + elements = zeros(Int64,nElements,4) + temp = zeros(Int64, 4) for i = 1:nElements values = split(readline(f)) for j = 1:4 - elements[i,j] = parse(Int, values[j]) + elements[i,j] = parse(Int64, values[j]) end values = split(readline(f)) for j = 1:4 - temp[j] = parse(Int, values[j]) + temp[j] = parse(Int64, values[j]) end if sum(temp) == 0 # straight-sided edge so just skip the boundary labels @@ -119,7 +119,7 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # Build the edges. This is only for plotting purposes so we might have some # repeated edges edge_id = 0 - edges = Dict{Int, Any}() + edges = Dict{Int64, Any}() for j in 1:nElements for k in 1:4 id1 = elements[j , p[1,k]] @@ -157,11 +157,11 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # number of corner nodes file_idx = findfirst(contains("*ELEMENT"), file_lines) - 1 current_line = split(file_lines[file_idx], ",") - nNodes = parse(Int, current_line[1]) + nNodes = parse(Int64, current_line[1]) # number of elements file_idx = findfirst(contains("** ***** HOHQMesh boundary information ***** **"), file_lines) - 1 current_line = split(file_lines[file_idx], ",") - nElements = parse(Int, current_line[1]) + nElements = parse(Int64, current_line[1]) # # Read in the nodes # @@ -177,13 +177,13 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # # Read the element ids (and skip all the boundary information) # - elements = zeros(Int, nElements, 4) + elements = zeros(Int64, nElements, 4) # eat the element header file_idx += 1 for i = 1:nElements current_line = split(file_lines[file_idx], ",") for j = 2:5 - elements[i,j-1] = parse(Int, current_line[j]) + elements[i,j-1] = parse(Int64, current_line[j]) end file_idx += 1 end @@ -193,7 +193,7 @@ function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractS # Build the edges. This is only for plotting purposes so we might have some # repeated edges edge_id = 0 - edges = Dict{Int, Any}() + edges = Dict{Int64, Any}() for j in 1:nElements for k in 1:4 id1 = elements[j , p[1,k]] From 57f3c17029f432e749a22beb45d09efa0284a070 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 12 Apr 2022 10:41:09 +0200 Subject: [PATCH 125/164] add compat for AbaqusReader to testing Project toml --- test/Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Project.toml b/test/Project.toml index 8704c3f9..0a3a17e0 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -4,4 +4,5 @@ CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] +AbaqusReader = "0.2.5" CairoMakie = "0.6, 0.7" \ No newline at end of file From e640d8f13faf85025ee96c2ba4182e6a9cb98969 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 12 Apr 2022 10:44:40 +0200 Subject: [PATCH 126/164] update the global license --- LICENSE.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 29449acb..15e2bdb7 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,21 +1,21 @@ MIT License -Copyright (c) 2021-present Michael Schlottke-Lakemper +Copyright (c) 2021-present David Kopriva, Andrew Winters, and Michael Schlottke-Lakemper -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From e57c590b7003a072e9096e7e9b5566d3ba30ec3a Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Tue, 12 Apr 2022 10:49:34 +0200 Subject: [PATCH 127/164] remove license from the individual files --- docs/src/license.md | 10 ++++----- src/ControlFile/ControlFileOperations.jl | 26 ------------------------ src/Curves/CurveOperations.jl | 25 ----------------------- src/Curves/Spline.jl | 25 ----------------------- src/Mesh/Meshing.jl | 25 ----------------------- src/Misc/DictionaryOperations.jl | 26 ------------------------ src/Misc/NotificationCenter.jl | 25 ----------------------- src/Model/Geometry.jl | 25 ----------------------- src/Project/BackgroundGridAPI.jl | 25 ----------------------- src/Project/ControlInputAPI.jl | 25 ----------------------- src/Project/CurvesAPI.jl | 25 ----------------------- src/Project/Generics.jl | 26 ------------------------ src/Project/ModelAPI.jl | 26 ------------------------ src/Project/Project.jl | 26 ------------------------ src/Project/RefinementRegionsAPI.jl | 25 ----------------------- src/Project/RunParametersAPI.jl | 25 ----------------------- src/Project/SmootherAPI.jl | 25 ----------------------- src/Project/Undo.jl | 25 ----------------------- src/Viz/VizMesh.jl | 25 ----------------------- src/Viz/VizProject.jl | 25 ----------------------- 20 files changed, 5 insertions(+), 485 deletions(-) diff --git a/docs/src/license.md b/docs/src/license.md index b696e593..b6038dab 100644 --- a/docs/src/license.md +++ b/docs/src/license.md @@ -1,19 +1,19 @@ # License > MIT License -> -> Copyright (c) 2021-present Michael Schlottke-Lakemper -> +> +> Copyright (c) 2021-present David Kopriva, Andrew Winters, and Michael Schlottke-Lakemper +> > Permission is hereby granted, free of charge, to any person obtaining a copy > of this software and associated documentation files (the "Software"), to deal > in the Software without restriction, including without limitation the rights > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > copies of the Software, and to permit persons to whom the Software is > furnished to do so, subject to the following conditions: -> +> > The above copyright notice and this permission notice shall be included in all > copies or substantial portions of the Software. -> +> > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index b71da7f5..2ef490e4 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -1,29 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - #= ImportControlFile(fileName::String) diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index 7e40d732..f23cdeff 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# const argRegex = r"(?<=\().+?(?=\))" diff --git a/src/Curves/Spline.jl b/src/Curves/Spline.jl index 2e5478bd..a9ec87ee 100644 --- a/src/Curves/Spline.jl +++ b/src/Curves/Spline.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# mutable struct Spline N::Int diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 2e572ae6..ccfdc3f3 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# function generate_mesh(proj::Project) # diff --git a/src/Misc/DictionaryOperations.jl b/src/Misc/DictionaryOperations.jl index f66a64e3..fca5c34d 100644 --- a/src/Misc/DictionaryOperations.jl +++ b/src/Misc/DictionaryOperations.jl @@ -1,29 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - #= Some useful getters for a dictionary =# diff --git a/src/Misc/NotificationCenter.jl b/src/Misc/NotificationCenter.jl index f6227497..86a5b884 100644 --- a/src/Misc/NotificationCenter.jl +++ b/src/Misc/NotificationCenter.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# struct HQMNotification sender ::Any # Who sent the notification diff --git a/src/Model/Geometry.jl b/src/Model/Geometry.jl index efbeea7e..bcabca84 100644 --- a/src/Model/Geometry.jl +++ b/src/Model/Geometry.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# const TOP = 1; const LEFT = 2; const BOTTOM = 3; const RIGHT = 4 diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 41657438..1c9f765d 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# """ addBackgroundGrid(proj::Project, bgSize::Array{Float64}) diff --git a/src/Project/ControlInputAPI.jl b/src/Project/ControlInputAPI.jl index 8b8a7443..6f27e44c 100644 --- a/src/Project/ControlInputAPI.jl +++ b/src/Project/ControlInputAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# function getControlDict(proj::Project) if haskey(proj.projectDictionary,"CONTROL_INPUT") diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 741233e6..3010ef16 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# """ newParametricEquationCurve(name::String, diff --git a/src/Project/Generics.jl b/src/Project/Generics.jl index b7ce4a96..92d15429 100644 --- a/src/Project/Generics.jl +++ b/src/Project/Generics.jl @@ -1,29 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - # # Creating curves # diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 04fd9b88..eeefbd64 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -1,29 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - # # -------------------------------------------------------------------------------------- # OUTER BOUNDARY FUNCTIONS diff --git a/src/Project/Project.jl b/src/Project/Project.jl index d015e6d4..9900cc84 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -1,29 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# - #= The Project is the controller in an MVC paradigm. It manages the model, stored in the projectDictionary, and plotting data, and responds to enableNotifications diff --git a/src/Project/RefinementRegionsAPI.jl b/src/Project/RefinementRegionsAPI.jl index 800b230a..2d23a474 100644 --- a/src/Project/RefinementRegionsAPI.jl +++ b/src/Project/RefinementRegionsAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# """ newRefinementCenter(name, type, diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index ea708cd2..f5d4e5fd 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# """ addRunParameters!(proj::Project, diff --git a/src/Project/SmootherAPI.jl b/src/Project/SmootherAPI.jl index 5da4c2cb..50e1aa4a 100644 --- a/src/Project/SmootherAPI.jl +++ b/src/Project/SmootherAPI.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# """ addSpringSmoother!(status::String, type::String, nIterations::Int) diff --git a/src/Project/Undo.jl b/src/Project/Undo.jl index 482d00bd..a1bdc8f2 100644 --- a/src/Project/Undo.jl +++ b/src/Project/Undo.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# struct UROperation object::Any diff --git a/src/Viz/VizMesh.jl b/src/Viz/VizMesh.jl index 4b3d3a4c..9c53ddeb 100644 --- a/src/Viz/VizMesh.jl +++ b/src/Viz/VizMesh.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# function getMeshFromMeshFile(meshFile::AbstractString, meshFileFormat::AbstractString) diff --git a/src/Viz/VizProject.jl b/src/Viz/VizProject.jl index a987acca..0d87c352 100644 --- a/src/Viz/VizProject.jl +++ b/src/Viz/VizProject.jl @@ -1,28 +1,3 @@ -#= - MIT License - - Copyright (c) 2010-present David A. Kopriva and other contributors: AUTHORS.md - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - - --- End License -=# const MODEL = 1; const GRID = 2; const MESH = 4; const EMPTY = 0 const REFINEMENTS = 8; const ALL = 15 From 08b0edbb04bbcd789f007131d8f1c1807446448b Mon Sep 17 00:00:00 2001 From: DavidAKopriva <85404032+DavidAKopriva@users.noreply.github.com> Date: Tue, 12 Apr 2022 11:27:08 -0700 Subject: [PATCH 128/164] Update src/Curves/CurveOperations.jl Co-authored-by: Jesse Chan --- src/Curves/CurveOperations.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index f23cdeff..b71f1b0b 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -215,10 +215,10 @@ function curvePoint(crvDict::Dict{String,Any}, t::Float64) end -function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}) +function curvesMeet(firstCurve::Dict{String,Any}, secondCurve::Dict{String,Any}; tol=100*eps(Float64)) xFirst = curvePoint(firstCurve,1.0) xSecond = curvePoint(secondCurve,0.0) - if maximum(abs.(xFirst - xSecond)) < 100*eps(Float64) + if maximum(abs.(xFirst - xSecond)) < tol return true else return false From 3710c10865db4669025ae96db177a2ab5900ff7c Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 12 Apr 2022 14:37:03 -0700 Subject: [PATCH 129/164] Edit documentation Edits to HQMTool.md --- docs/src/HQMTool.md | 100 +++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 48 deletions(-) diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 42f12aff..93f84677 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -1,25 +1,25 @@ # HQMTool -HQMTool is currently an API to generate a quad (Future:Hex) mesh using Julia. +HQMTool is an API to generate a quad (Future:Hex) mesh using Julia. It serves as a front end to the HOHQMesh program, and is designed to let one build a meshing project interactively while graphically displaying the results. ## Contents 1. [Introduction](@ref) 2. [Basic Moves](@ref) 3. [HQMTool API](@ref) - 1. [Project Creation and Saving](@ref) - 2. [Plotting](@ref) - 3. [Modifying/Editing a Project](@ref) - 4. [Controlling the Mesh Generation Process](@ref) +1. [Project Creation and Saving](@ref) +2. [Plotting](@ref) +3. [Modifying/Editing a Project](@ref) +4. [Controlling the Mesh Generation Process](@ref) 1. [Editing the Run Parameters](@ref) 2. [Changing the output file names](@ref) 3. [Adding the background grid](@ref) 4. [Smoothing Operations](@ref) 5. [Manual Refinement](@ref) - 5. [Boundary Curves](@ref) +5. [Boundary Curves](@ref) 1. [Adding and Removing Outer and Inner Boundaries](@ref) 2. [Defining Curves](@ref) 3. [Editing Curves](@ref) - 6. [Undo/Redo](@ref) +6. [Undo/Redo](@ref) 4. [Advanced](@ref) ## Introduction @@ -67,7 +67,7 @@ boundary in the shape of an ice cream cone. The "verbose" version of the script if called_by_user # - # Show the model and grid + # Show the model and grid # plotProject!(p, MODEL+GRID) println("Press enter to continue and generate the mesh") @@ -85,23 +85,23 @@ The first line creates a new project, where the mesh and plot file names will be from the project name, "IceCreamCone" written to the specified folder. To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, -if desired. As in HOHQMesh, there are four curve classes currently operational: +if desired. As in HOHQMesh, there are four curve classes currently available: - Parametric equations -- Splines +- Cubic Splines - Lines defined by their end points - Circular arcs In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with -`addCurveToOuterBoundary!` through the generic name `add!`. You can add any number of curves, +`addCurveToOuterBoundary!`. You can add any number of curves to the outer boundary, but they must be added in order, counter-clockwise. Similarly, you create curves and add them to as many inner boundaries that you want to have. -In the example, there is one inner boundary, "IceCreamCone" made up of two lines and a half -circular arc. Again, add them in order, counter-clockwise. +In the example, there is one inner boundary, "IceCreamCone" made up of two straight lines and a half +circular arc. Again, they are added in order, counter-clockwise. -For convenience, `newProject` will generate default run parameters, like the plot file format +For convenience, `newProject` will generate default run parameters used by HOHQMesh, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). @@ -119,7 +119,7 @@ The script finishes by generating the quad mesh and plotting the results, as sho ![iceCreamCone](https://user-images.githubusercontent.com/25242486/162193980-b80fb92c-2851-4809-af01-be856152514f.png) -It also returns the project so that it can be edited further, if desired. +Finally, the script returns the project so that it can be edited further, if desired. To save a control file for HOHQMesh, simply invoke ``` @@ -129,7 +129,7 @@ where outFile is the name of the control file (traditionally with a .control ext `saveProject` is automatically called when a mesh is generated. The third example `ice_cream_cone_demo` is identical to that which was explained above -except that the function calls use the generic version of, e.g., `new` or `add!`. +except that the function calls use the generic versions of functions, e.g., `new` or `add!`. Methods are available to edit a model. For example to move the center of the outer boundary. @@ -146,19 +146,23 @@ To generate a mesh using HQMTool you 2. [Create inner and outer boundary curves](#DefiningCurves) ``` - c = new(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* - c = new(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* - c = new(, xEqn, yEqn, zEqn) *Parametric equation* - c = new(, dataFile) *Spline with data from a file* - c = new(, nKnots, knotsMatrix) *Spline with given knot values* + c = newEndPointsLineCurve(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* + c = newCircularArcCurve(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* + c = newParametricEquationCurve(, xEqn, yEqn, zEqn) *Parametric equation* + c = newSplineCurve(, dataFile) *Spline with data from a file* + c = newSpline(, nKnots, knotsMatrix) *Spline with given knot values* ``` +The generic name for each of these curve creation methods is `new!. The generic can be used instead of the longer descriptive name to save typing during interactive sessions, if desired. + + 3. [Add curves](#AddingCurves) to build the model to see what you have added, ``` - add!(p, ) *Add outer boundary curve* - add!(p, , ) *Add curve to an inner boundary* + addOuterBoundaryCurve!(p, ) *Add outer boundary curve* + addInnerBoundaryCurve!(p, , ) *Add curve to an inner boundary* ``` +Curves can be added by using the generic `add!` function instead of the longer descriptive name to save typing during interactive sessions, if desired. 4. To [visualize](#Plotting) the project's model, @@ -166,19 +170,19 @@ To generate a mesh using HQMTool you plotProject!(p, MODEL) ``` - To update the plot at any time, use + Plots are updated in response to user interactions. However, to update the plot at any time, use ``` updatePlot!(p, options) ``` Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. - `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not intersted in the background grid once + `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not interested in the background grid once the mesh is generated.) 5. Set the [background grid](#(#BackgroundGrid)) - When no outer boundary curve is present the background grid can be set with + When no outer boundary curve is present, the background grid can be set with ``` addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) @@ -192,12 +196,12 @@ To generate a mesh using HQMTool you The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent - [top value, left value, bottom value, right value] and the number of elements in each direction. + [top value, left value, bottom value, right value] and the number of elements in each direction. The first exists for historical reasons; the second is probably the easiest to use. When an outer boundary is present the background grid can be set as ``` - addBackgroundGrid!(p, grid size [dx,dy,dz]) + addBackgroundGrid!(p,[dx,dy,dz]) ``` where the spacing controls the number of elements in each direction. @@ -214,13 +218,15 @@ To generate a mesh using HQMTool you generate_mesh(p) ``` -The mesh will be stored in `` with the name `.mesh`. The control file will also be -saved in that folder with the name `.control`, which you can read in again later and modify, -remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in -the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` -command. + The mesh will be stored in `` with the name `.mesh`. The control file will also be + saved in that folder with the name `.control`, which you can read in again later and modify, + remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in + the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` + command. +The ordering of the basic moves follows a logical pattern: The project must be created first. Curves can be added at any time, but adding curve segments to a curve must be done in order. The background grid can be added any time to the project. A mesh is ususally generated after the model (curves) and background grid are completed. + ## HQMTool API ### Project Creation and Saving @@ -259,14 +265,13 @@ It can be read in again with `openProject`. The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, which you an view to make sure that it can resolve the boundary curves in the model. Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show -where [manual refinement](#ManualRefinement) is added. +where [manual refinement](#ManualRefinement) is placed. If the model is modified and you want to re-plot with the new values, invoke ``` updatePlot!(proj::Project, options) ``` -but genrally the plot will be updated automatically as you build the model. - +but generally the plot will be updated automatically as you build the model. ### Modifying/Editing a Project @@ -361,8 +366,8 @@ To create a refinement center, h::Float64, w::Float64) ``` -where the type is either `smooth` or `sharp`, `x0` = [x, y, z] is the location of the center, `h` is the mesh size, -and `w` is the extent of the refinement region. +where the type is either "smooth" or "sharp", `x0` = [x, y, z] is the location of the center, `h` is the mesh size, +and `w` is the extent of the refinement region. The z component must be zero. Similarly, one can create a `RefinementLine`, ``` @@ -378,9 +383,8 @@ To add a refinement region to the project, [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) ``` -To get the indx'th refinement region from the project, or to get a refinement region with a given name, use +To get a reference to a refinement region with a given name, use ``` - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, indx::Int) [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) ``` @@ -389,7 +393,7 @@ Finally, to get a list of all the refinement regions, [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) ``` -A refinement region can be edited by using the following +A refinement region can be edited by using the following: ``` [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) [Return:String] getRefinementType(r::Dict{String,Any}) @@ -435,8 +439,8 @@ To further edit a `RefinementLine`, use the methods 2. Adding an inner boundary curve - The syntax is analogous to the creation of an outer boundary curve where, again, curve creation must - be ordered counter-clockwise. + The syntax is analogous to the creation of an outer boundary curve where, again, curve segments added to an inner curve with a given name must + in order, counter-clockwise. ``` [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @@ -465,7 +469,7 @@ To further edit a `RefinementLine`, use the methods ``` [Return:nothing] removeOuterBoundary!(proj::Project) - [Return:nothing] removeInnerBoundary!(proj::Project, chainName::String) + [Return:nothing] removeInnerBoundary!(proj::Project, boundaryName::String) ``` Alternatively, individual pieces of the boundary curve chains can be removed. @@ -485,7 +489,7 @@ To further edit a `RefinementLine`, use the methods Four curve types can be added to the outer and inner boundary curve chains. They are - Parametric equations -- Splines +- Cubic Splines - Lines defined by their end points - Circular arcs @@ -513,9 +517,9 @@ Example: ``` The z-Equation is optional, but for now must define zero for z by default. -##### Spline Curve +##### Cubic Spline Curve -A spline is defined by an array of knots, tj,xj,yj,zj. +A cubic spline is defined by an array of knots, tj,xj,yj,zj. It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define the t,x,y,z values, e.g. ``` @@ -530,7 +534,7 @@ the t,x,y,z values, e.g. 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 ``` -or by constructing the `nKnots` by `4` array supplying it to the new procedure. The respective constructors are +or by constructing the `nKnots` x `4` array and supplying it to the new procedure. The respective constructors are ``` [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) Generic: new(...) From 96260d950508074258dcddf94937cc3843547dc1 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Tue, 12 Apr 2022 14:48:34 -0700 Subject: [PATCH 130/164] Update ControlFileOperations.jl Complete the description of the condtrol file dictionary. --- src/ControlFile/ControlFileOperations.jl | 104 ++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/src/ControlFile/ControlFileOperations.jl b/src/ControlFile/ControlFileOperations.jl index 2ef490e4..8827143d 100644 --- a/src/ControlFile/ControlFileOperations.jl +++ b/src/ControlFile/ControlFileOperations.jl @@ -13,7 +13,6 @@ A Control file dictionary contains the keys TYPE is a string naming the type (class) of object stored The CONTROL_INPUT contains the blocks - TYPE RUN_PARAMETERS MESH_PARAMETERS SPRING_SMOOTHER @@ -55,10 +54,111 @@ A PARAMETRIC_EQUATION_CURVE dictionary contains the keys yEqn zEqn +A SPLINE_CURVE block contains the keys + TYPE + name + SPLINE_DATA + +SPLINE_DATA block contains keys and data + nKnots + t_1 x_1 y_1 z_1 + t_2 x_2 y_2 z_2 + ... + t_nKnots x_nKnots y_nKnots z_nKnots + +An END_POINTS_LINE has the following keys + TYPE + name + xStart + xEnd + +A CIRCULAR_ARC block contains + TYPE + name + units + center + radius + start angle + end angle + +REFINEMENT_REGIONS dictionary contains the keys + TYPE + LIST + LIST is a list of + REFINEMENT_CENTER + REFINEMENT_LINE + +A REFINEMENT_CENTER contains the keys + TYPE + center + h + w + +A REFINEMENT_LINE contains the keys + TYPE + xStart + xEnd + h + w + +A ROTATION_TRANSFORMATION contains the keys + TYPE + direction + rotationPoint + +A SCALE_TRANSFORMATION contains the keys + TYPE + origin + scaleFactor + +The SWEEP_CURVE dictionary contains the keys + TYPE + LIST + The list contains dictionaries describing + PARAMETRIC_EQUATION_CURVE + SPLINE_CURVE + END_POINTS_LINE + +The SWEEP_SCALE_FACTOR dictionary contains the keys + TYPE + LIST + The list contains dictionaries describing + PARAMETRIC_EQUATION + + But the equation definitions contain only one equation r(t) = ... + +The TOPOGRAPHY dictionary contains the keys + TYPE + eqn (for equation defined topography) + sizing + +The SIMPLE_EXTRUSION block contains the keys + TYPE + direction + height + subdivisions + start surface name + end surface name + +The SIMPLE_ROTATION block contains the keys + TYPE + direction + rotation angle factor + subdivisions + start surface name + end surface name + +The SWEEP_ALONG_CURVE block contains the keys + TYPE + algorithm (optional) + subdivisions per segment + start surface name + end surface name + =# # Four objects store their members as lists rather than -# as dictionaries +# as dictionaries (See above) const blocksThatStoreLists = Set(["OUTER_BOUNDARY", "REFINEMENT_REGIONS" , From d9cfb635fe44d2ea0e0206597ef52eb6fa004323 Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Wed, 13 Apr 2022 16:50:36 -0700 Subject: [PATCH 131/164] Add routines to check integrity of boundary curves Two new routines. Called before a mesh is generated. Generates warnings if curves are not in order or chains are not closed. --- src/Mesh/Meshing.jl | 6 +++++ src/Project/ModelAPI.jl | 9 ++++--- src/Project/Project.jl | 54 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index ccfdc3f3..dc49a636 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -8,6 +8,12 @@ function generate_mesh(proj::Project) @warn "A background grid is needed before meshing. Add one and try again." return nothing end + + if !modelCurvesAreOK(proj) + @warn "Meshing aborted: Ensure boundary curve segments are in order and boundary curves are closed and try again." + return nothing + end + saveProject(proj) fileName = joinpath(proj.projectDirectory,proj.name)*".control" mesherOutput = generate_mesh(fileName, output_directory = proj.projectDirectory) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index eeefbd64..e5309160 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -163,8 +163,6 @@ function getOuterBoundaryChainList(proj::Project) return lst end end - - # # -------------------------------------------------------------------------------------- # INNER BOUNDARY FUNCTIONS @@ -442,8 +440,13 @@ function innerBoundaryIndices(proj::Project, curveName::String) end return (0,0) end +#= + CHAIN OPERATIONS +=# - +#= + OTHER +=# function getModelDict(proj::Project) if haskey(proj.projectDictionary,"MODEL") return proj.projectDictionary["MODEL"] diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 9900cc84..e5866228 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -399,3 +399,57 @@ function meshWasDeleted(proj::Project, sender::Project) updatePlot!(proj, options) end end + +""" + modelCurvesAreOK(proj::Project) + +Go through all curves in the model and make sure they are connected and closed. + +Returns true if all curves are connected and closed, false otherwise. +""" +function modelCurvesAreOK(proj::Project) + result = true + + chain = getOuterBoundaryChainList(proj) + if !isempty(chain) + result = modelChainIsOK(chain,"Outer") + end + + innerBoundariesList = getAllInnerBoundaries(proj) + + for chain in innerBoundariesList + chainName = string(chain["name"]) + chainList = chain["LIST"] + result = result && modelChainIsOK(chainList,chainName) + end + + return result +end +""" + modelChainIsOK(chain::Vector{Dict{String, Any}}, chainName::String) + +Returns true if the chain of curves is contiguous and closed; false otherwise. +""" +function modelChainIsOK(chain::Vector{Dict{String, Any}}, chainName::String) + result = true + for i in 1:length(chain)-1 + crv1 = chain[i] + crv2 = chain[i+1] + if !curvesMeet(crv1,crv2) + name1 = getCurveName(crv1) + name2 = getCurveName(crv2) + @warn "The curve $name2 does not meet the previous curve, $name1." + result = false + end + end + crv1 = last(chain) + crv2 = chain[1] + if !curvesMeet(crv1,crv2) + name1 = getCurveName(crv1) + name2 = getCurveName(crv2) + @warn "The boundary curve $chainName is not closed. Fix to generate mesh" + result = false + end + + return result +end From 7f52b2e516c3df8adb970b201078bcd95de0697e Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 10:53:27 +0200 Subject: [PATCH 132/164] add some comments as suggested in review --- src/Curves/CurveOperations.jl | 4 ---- src/Curves/Spline.jl | 5 +++-- src/Mesh/Meshing.jl | 7 ++++++- src/Project/Undo.jl | 3 ++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Curves/CurveOperations.jl b/src/Curves/CurveOperations.jl index b71f1b0b..c55aa623 100644 --- a/src/Curves/CurveOperations.jl +++ b/src/Curves/CurveOperations.jl @@ -161,10 +161,6 @@ function curvePoints(crvDict::Dict{String,Any}, N::Int) M = max(N,nKnots*2) x = zeros(Float64,M+1,2) - t = zeros(Float64,M+1) - for i = 1:M+1 - t[i] = (i-1)/M - end splineCurvePoints(nKnots,splineData,x) end diff --git a/src/Curves/Spline.jl b/src/Curves/Spline.jl index a9ec87ee..d93d8501 100644 --- a/src/Curves/Spline.jl +++ b/src/Curves/Spline.jl @@ -16,7 +16,7 @@ function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) Nm1 = N - 1 # -# Set up tri-diagonal system +# Set up tri-diagonal system for a cubic spline # d[1] = x[2] - x[1] c[2] = (y[2] - y[1])/d[1] @@ -27,7 +27,8 @@ function constructSpline(N::Int, x::Array{Float64},y::Array{Float64}) c[i] = c[i+1] - c[i] end # -# end conditions +# "not-a-knot" end conditions where third derivatives are approximated +# with divided differences # b[1] = -d[1] b[N] = -d[N-1] diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index dc49a636..c873db62 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -8,7 +8,7 @@ function generate_mesh(proj::Project) @warn "A background grid is needed before meshing. Add one and try again." return nothing end - + if !modelCurvesAreOK(proj) @warn "Meshing aborted: Ensure boundary curve segments are in order and boundary curves are closed and try again." return nothing @@ -23,6 +23,11 @@ function generate_mesh(proj::Project) end +""" + remove_mesh!(proj::Project) + +Remove the mesh file from `proj.projectDirectory` and delete the mesh from the plot +""" function remove_mesh!(proj::Project) meshFile = getMeshFileName(proj) rm(meshFile) diff --git a/src/Project/Undo.jl b/src/Project/Undo.jl index a1bdc8f2..e7c9d019 100644 --- a/src/Project/Undo.jl +++ b/src/Project/Undo.jl @@ -15,7 +15,8 @@ end #= TODO: The undo framework currently works globally, within the REPL. It *should* work project-by-project. -To make it project based, undo() would be replaced by undo(project) and an .undoStack +Note that these projects refer to the `HQMTool` projects, not Julia projects in the sense of `Project.toml`. +To make the undo framework project based, undo() would be replaced by undo(project) and an .undoStack property of the project would replace HQMglobalUndoStack. This is not a big deal except if multiple projects are open, and muliple objects like curves have been defined but not added to a project. In interactive mode curves are separate from projects until From 5ef82839edf69e1dc0781a6d91423c034e295546 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 12:03:19 +0200 Subject: [PATCH 133/164] add tests for the internal modelCurvesAreOK function --- src/Project/ModelAPI.jl | 3 +-- test/test_model.jl | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index e5309160..23ad286e 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -122,7 +122,7 @@ end """ - removeOuterboundary!(proj::Project) + removeOuterBoundary!(proj::Project) Remove the outer boundary curve if it exists. """ @@ -130,7 +130,6 @@ function removeOuterBoundary!(proj::Project) modelDict = getModelDict(proj) if haskey(modelDict,"OUTER_BOUNDARY") ob = modelDict["OUTER_BOUNDARY"] - println(ob) registerWithUndoManager(proj,addOuterBoundary!, (ob,), "Remove Outer Boundary") delete!(modelDict,"OUTER_BOUNDARY") proj.outerBndryPoints = Any[] diff --git a/test/test_model.jl b/test/test_model.jl index c55fc9fa..bc2b8973 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -11,7 +11,7 @@ Functions: @ = tested @@ insertOuterBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int) @@ removeOuterBoundaryCurveAtIndex!(proj::Project, indx::Int) @@ addOuterBoundary!(proj::Project, outerBoundary::Dict{String,Any}) - @ removeOuterboundary!(proj::Project) + @ removeOuterBoundary!(proj::Project) @ getOuterBoundaryChainList(proj::Project) @@ addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) @@ -65,11 +65,20 @@ using Test @test getChainIndex(obList,"obc3") == 3 @test undoActionName() == "Add Outer Boundary Curve" undo() + @test length(obList) == 2 + + # Check the outer boundary curve that are not conneted. Throws a warning + @test_logs (:warn, "The boundary curve Outer is not closed. Fix to generate mesh" ) HOHQMesh.modelCurvesAreOK(p) + @test HOHQMesh.modelCurvesAreOK(p) == false + @test redoActionName() == "Remove Outer Boundary Curve" redo() @test length(obList) == 3 + # Outer boundary is connected again. Check is successful now + @test HOHQMesh.modelCurvesAreOK(p) == true + crv = getOuterBoundaryCurveWithName(p,"obc2") @test getCurveName(crv) == "obc2" # @@ -101,6 +110,10 @@ using Test removeInnerBoundaryCurve!(p,"obc2",ib1Name) @test length(ibList) == 2 + # Check the inner boundary curve that are not conneted. Throws a warning + @test_logs (:warn, "The curve obc3 does not meet the previous curve, obc1.") HOHQMesh.modelCurvesAreOK(p) + @test HOHQMesh.modelCurvesAreOK(p) == false + undo() @test length(ibList) == 3 ibc = getInnerBoundaryCurve(p, "obc2",ib1Name) From ea26a68d65fcb5b36c496fa1d31d1dd52920d778 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 12:40:33 +0200 Subject: [PATCH 134/164] throw an error if one tries to remove an outer boundary curve that is not present --- src/Project/ModelAPI.jl | 3 +++ test/test_model.jl | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 23ad286e..fe5dd77a 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -48,6 +48,9 @@ function removeOuterBoundaryCurveWithName!(proj::Project, name::String) if indx > 0 proj.backgroundGridShouldUpdate = true removeOuterBoundaryCurveAtIndex!(proj,indx) # posts undo/notification + else + # `name` to be deleted does not lie in outer boundary chain. Throw an error. + error("No curve ", name, " in boundary Outer. Try again.") end end diff --git a/test/test_model.jl b/test/test_model.jl index bc2b8973..80a87fc8 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -84,6 +84,10 @@ using Test # # Test remove/add outer boundary # + + # Attempt to remove an outer boundary curve that does not exist. Throws an error + @test_throws ErrorException removeOuterBoundaryCurveWithName!(p, "wrongName") + removeOuterBoundary!(p) mDict = getModelDict(p) @test haskey(mDict,"OUTER_BOUNDARY") == false From 7d6b07649672ed90cb4a9bfe8cf63940bf46fd72 Mon Sep 17 00:00:00 2001 From: Hendrik Ranocha Date: Thu, 14 Apr 2022 13:39:17 +0200 Subject: [PATCH 135/164] dummy commit testing GitHub for Andrew From 4c753f9898e2b6b01c5fe943833cf26a8b2dcaf1 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 15:10:35 +0200 Subject: [PATCH 136/164] switch off demo tests --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index bdad93a6..5d050bf6 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -63,7 +63,7 @@ include("test_curve.jl") include("test_model.jl") # HQMTool demonstration test routines -include("test_hqmtool_demos.jl") +#include("test_hqmtool_demos.jl") # HQMTool project test routines include("test_hqmtool_project.jl") From 468e8fbce2ff4e0d2482360da03a5422dd6a5e4d Mon Sep 17 00:00:00 2001 From: David Kopriva Date: Sat, 16 Apr 2022 11:28:09 -0700 Subject: [PATCH 137/164] Changes to curve adding behavior Allow curves to be inserted out of order, with a check before meshing to ensure that ultimately boundary curves are in order and closed. --- docs/src/CheatSheet.md | 4 ++ docs/src/HQMTool.md | 13 ++--- src/Project/ModelAPI.jl | 103 +++++++++++++++++++--------------------- 3 files changed, 58 insertions(+), 62 deletions(-) diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index b0fbea20..a7c6d200 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -21,6 +21,7 @@ Workflow: updatePlot!(p, options) ``` +`options` are the sum of `GRID`, `MESH`, `MODEL`, `REFINEMENTS` ## Curves ``` @@ -31,6 +32,8 @@ Workflow: c = new(name, nKnots, knotsMatrix) *Spline with given knot values* ``` +Shown here is the use of the function `new`, which is a shortcut to the full functions, e.g. `newCircularArcCurve`, etc. which have the same arguments. + ## [Manual Refinement](@id cs-manual-refinement) ``` @@ -48,6 +51,7 @@ Workflow: addBackgroundGrid!(p, [top, left, bottom, right], [nX, nY, nZ]) *No outer boundary* addBackgroundGrid!(p, [dx, dy, dz]) *If an outer boundary is present* ``` +Shown here is the use of the function `add!`, which is a shortcut to the full functions, e.g. `addOuterBoundaryCurve`, etc. which have the same arguments. ## Accessing items diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 93f84677..1d8bcd47 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -94,12 +94,11 @@ if desired. As in HOHQMesh, there are four curve classes currently available: In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] with radius 4, starting at zero and ending at 360 degrees. It is added to the project with -`addCurveToOuterBoundary!`. You can add any number of curves to the outer boundary, -but they must be added in order, counter-clockwise. +`addCurveToOuterBoundary!`. You can add any number of curves to the outer boundary. Similarly, you create curves and add them to as many inner boundaries that you want to have. In the example, there is one inner boundary, "IceCreamCone" made up of two straight lines and a half -circular arc. Again, they are added in order, counter-clockwise. +circular arc. Again, they are defined counter-clockwise. For convenience, `newProject` will generate default run parameters used by HOHQMesh, like the plot file format and the smoother. The parameters can be edited with setter commands. For example, the script @@ -225,7 +224,7 @@ Curves can be added by using the generic `add!` function instead of the longer d command. -The ordering of the basic moves follows a logical pattern: The project must be created first. Curves can be added at any time, but adding curve segments to a curve must be done in order. The background grid can be added any time to the project. A mesh is ususally generated after the model (curves) and background grid are completed. +The ordering of the basic moves follows a logical pattern: The project must be created first. Curves can be added at any time. The background grid can be added any time to the project. A mesh is ususally generated after the model (curves) and background grid are completed. ## HQMTool API @@ -420,8 +419,7 @@ To further edit a `RefinementLine`, use the methods 1. Adding an outer boundary curve - Using the curve creation routines, described in the next section below, create curves in sucessive - order counter-clockwise along the outer boundary and add them to the outer boundary curve using + Using the curve creation routines, described in the next section below, create curves counter-clockwise along the outer boundary and add them to the outer boundary curve using ``` [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) @@ -439,8 +437,7 @@ To further edit a `RefinementLine`, use the methods 2. Adding an inner boundary curve - The syntax is analogous to the creation of an outer boundary curve where, again, curve segments added to an inner curve with a given name must - in order, counter-clockwise. + The syntax is analogous to the creation of an outer boundary curve where. ``` [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index fe5dd77a..f1c64690 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -10,33 +10,15 @@ Add a curve to the outer boundary. The curves must be added in order counter-clo """ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) chain = getOuterBoundaryChainList(proj) -# -# Check if the new curve meets the last one added -# - if !isempty(chain) - lastCurve = last(chain) - if !curvesMeet(lastCurve,crv) - lastName = getCurveName(lastCurve) - newName = getCurveName(crv) - @warn "The curve $lastName does not meet the previous curve, $newName. Try again." - return - end - end -# -# Checks out, add to model -# - push!(chain,crv) - crvPoints = curvePoints(crv,defaultPlotPts) - push!(proj.outerBndryPoints, crvPoints) - proj.backgroundGridShouldUpdate = true + i = chainInsertionIndex(crv,chain) - push!(proj.outerBndryNames,crv["name"]) + enableNotifications() + insertOuterBoundaryCurveAtIndex!(proj,crv,i) - registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Outer Boundary Curve") - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) + enableUndo() + registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") end - """ removeOuterBoundaryCurveWithName!(proj::Project, name::String) @@ -178,41 +160,18 @@ does not exist, one is created. """ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - i, chain = getInnerBoundaryChainWithName(proj,boundaryName) + i, chain = getInnerBoundaryChainWithName(proj,boundaryName) curveList = chain["LIST"] -# -# Check if the new curve meets the last one added -# - if !isempty(curveList) - lastCurve = last(curveList) - if !curvesMeet(lastCurve,crv) - lastName = getCurveName(lastCurve) - newName = getCurveName(crv) - @warn "The curve $lastName does not meet the previous curve, $newName. Try again." - return - end - end -# -# Checks out, add to model -# - push!(curveList,crv) + j = chainInsertionIndex(crv,curveList) - if i > length(proj.innerBoundaryPoints) # New inner boundary chain - a = [] - push!(a,curvePoints(crv,defaultPlotPts)) - push!(proj.innerBoundaryPoints,a) - else - a = proj.innerBoundaryPoints[i] - push!(a,curvePoints(crv,defaultPlotPts)) - end - push!(proj.innerBoundaryNames[i],crv["name"]) + enableNotifications() + insertInnerBoundaryCurveAtIndex!(proj,crv,j,boundaryName) + enableUndo() registerWithUndoManager(proj,removeInnerBoundaryCurve!, (crv["name"],boundaryName), "Add Inner Boundary Curve") - postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end - """ removeInnerBoundaryCurve!(proj::Project, name::String) @@ -247,14 +206,23 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) end -function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, +function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int, boundaryName::String) i, chain = getInnerBoundaryChainWithName(proj,boundaryName) lst = chain["LIST"] insert!(lst,indx,crv) + + if i > length(proj.innerBoundaryPoints) # New inner boundary chain + a = [] + push!(a,curvePoints(crv,defaultPlotPts)) + push!(proj.innerBoundaryPoints,a) + else innerBoundaryPoints = proj.innerBoundaryPoints[i] insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) - insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + end + insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + + proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end @@ -445,7 +413,34 @@ end #= CHAIN OPERATIONS =# - +function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{String, Any}}) + #= + See if the endpoints of crv match up to any of the curves in the chainList. If so, + return the index where crv should be inserted into the list. + =# + + if isempty(chainList) + return 1 # Make crv the start of the chain. + end + # + nCurves = length(chainList) + if curvesMeet(chainList[nCurves],crv) + return nCurves+1 # Check first in likely case that user inputs in order + end + # + # Search though list of curves to see if the start of crv matches + # the end of one of the curves already in the chain. Linear search because + # it's easy and likely the list will not be that large. + # + for i in 1:nCurves + if curvesMeet(chainList[i],crv) + return i+1 # Add after the curve that matches. + end + end + + return nCurves+1 # No match, so just append to the list + end + #= OTHER =# From 91c57ea08356e4de344fba0f9405199caa9050ce Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 20:14:16 +0200 Subject: [PATCH 138/164] properly export the examples folder --- docs/src/index.md | 2 +- src/HOHQMesh.jl | 38 +++++++++++++++++++---------------- test/runtests.jl | 10 ++++----- test/test_hqmtool_project.jl | 4 ++-- test/test_project_with_viz.jl | 2 +- 5 files changed, 30 insertions(+), 26 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 992defcd..c2db6000 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -33,7 +33,7 @@ Two 2D examples `GingerbreadMan` and `NACA0012` and a 3D example `Snake` (all from HOHQMesh itself) come delivered with this package. You can generate a mesh for them by executing ```julia -julia> control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") +julia> control_file = joinpath(examples_dir(), "GingerbreadMan.control") julia> output = generate_mesh(control_file) ``` diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index c5693fa2..6bdb20f7 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -22,8 +22,12 @@ end # Main wrapper to generate a mesh from a control file export generate_mesh +# Make the examples directory available to the user +export examples_dir + # Functions useful to demonstrate the interactive HQMTool -export run_demo, ice_cream_cone_verbose_demo, ice_cream_cone_demo +#export run_demo, ice_cream_cone_verbose_demo, ice_cream_cone_demo +export ice_cream_cone_verbose_demo, ice_cream_cone_demo # Generic functions for the HQMTool interface export new, @@ -338,22 +342,22 @@ include("Mesh/Meshing.jl") #---------------- Routines for demonstrating the HQMTool --------------------------------- # -function run_demo(folder::String; called_by_user=true) -# -# Reads in an existing control file, plots the boundary curves and generates -# a mesh. -# - all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) - p = openProject(all_features_control_file, folder) - - plotProject!(p, MODEL+REFINEMENTS+GRID) - println("Press enter to continue and generate the mesh") - if called_by_user - readline() - end - generate_mesh(p) - return p -end +# function run_demo(folder::String; called_by_user=true) +# # +# # Reads in an existing control file, plots the boundary curves and generates +# # a mesh. +# # +# all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) +# p = openProject(all_features_control_file, folder) + +# plotProject!(p, MODEL+REFINEMENTS+GRID) +# println("Press enter to continue and generate the mesh") +# if called_by_user +# readline() +# end +# generate_mesh(p) +# return p +# end function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) diff --git a/test/runtests.jl b/test/runtests.jl index 5d050bf6..4c13417a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,21 +9,21 @@ isdir(outdir) && rm(outdir, recursive=true) @testset "HOHQMesh.jl" begin @testset "examples_dir()" begin - @test occursin("examples", HOHQMesh.examples_dir()) + @test occursin("examples", examples_dir()) end @testset "generate_mesh()" begin - control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") + control_file = joinpath(examples_dir(), "GingerbreadMan.control") @test generate_mesh(control_file) isa String end @testset "generate_mesh(; verbose=true)" begin - control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") + control_file = joinpath(examples_dir(), "GingerbreadMan.control") @test generate_mesh(control_file, verbose=true) isa String end @testset "generate_mesh() in 2D with ABAQUS output" begin - control_file = joinpath(HOHQMesh.examples_dir(), "IceCreamCone_Abaqus.control") + control_file = joinpath(examples_dir(), "IceCreamCone_Abaqus.control") generate_mesh(control_file) parse_mesh = abaqus_read_mesh(joinpath(outdir, "IceCreamCone_Abaqus.inp")) # set some reference values for comparison. These are the corner IDs for element 114 @@ -32,7 +32,7 @@ isdir(outdir) && rm(outdir, recursive=true) end @testset "generate_mesh() in 3D with ABAQUS output" begin - control_file = joinpath(HOHQMesh.examples_dir(), "HalfCircle3DRot.control") + control_file = joinpath(examples_dir(), "HalfCircle3DRot.control") generate_mesh(control_file) parse_mesh = abaqus_read_mesh(joinpath(outdir, "HalfCircle3DRot.inp")) # set some reference values for comparison. These are the corner IDs for element 246 diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index aca6076f..3bc0bdde 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -48,7 +48,7 @@ using Test @test haskey(cDict,"SPRING_SMOOTHER") == false # read in the AllFeatures example - control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") + control_file = joinpath(examples_dir(), "AllFeatures.control") p = openProject(control_file, projectPath) @test hasBackgroundGrid(p) == true @@ -73,7 +73,7 @@ using Test HOHQMesh.stringForKeyFromDictionary("CONTROL_INPUT", p.projectDictionary) # Use the NACA0012 example because it sets the background grid differently - control_file = joinpath(HOHQMesh.examples_dir(), "NACA0012.control") + control_file = joinpath(examples_dir(), "NACA0012.control") p = openProject(control_file, projectPath) sizes = [2.0, 2.0, 1.0] diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 8f446fcb..48b357ad 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -66,7 +66,7 @@ using CairoMakie projectPath = "out" - control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") + control_file = joinpath(examples_dir(), "AllFeatures.control") p_file = openProject(control_file, projectPath) @test_nowarn plotProject!(p_file, MODEL+GRID) From b48611ebaace2bc3bfab9985e6fedb732bba1cd2 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 14 Apr 2022 20:16:28 +0200 Subject: [PATCH 139/164] move runDemo into an external example script --- examples/interactive_from_control_file.jl | 34 +++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/interactive_from_control_file.jl diff --git a/examples/interactive_from_control_file.jl b/examples/interactive_from_control_file.jl new file mode 100644 index 00000000..7ae03e54 --- /dev/null +++ b/examples/interactive_from_control_file.jl @@ -0,0 +1,34 @@ +# Interactive mesh from a HOHQMesh control file +# +# Reads in the `AllFeatures.control` file, creates a `HQMTool` project, +# and generates a mesh file. More details abuot the outer / inner boundary +# curves, refinement regions, etc. of HOHQMesh can be found in its documentation +# https://trixi-framework.github.io/HOHQMesh/ +# +# Keywords: outer boundary chain, inner boundary chain, refinement region, control file read in + +using HOHQMesh + +# Set the file path of the control file to be read in for this example + +all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) + +# Read in the HOHQMesh control file and create the project dictionary that stores +# the different components of a mesh, i.e., boundary curves, refinement regions, etc. +# as well as set the output folder where any generated files will be saved. + +p = openProject(all_features_control_file, "out") + +# To plot the project, type `using GLMakie` in the REPL session, uncomment this line, and rerun +# this script + +# plotProject!(p, MODEL+REFINEMENTS+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL \ No newline at end of file From 8be0539284a7247e93ee881a43e47cc1deb47bfd Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 15 Apr 2022 17:57:32 +0200 Subject: [PATCH 140/164] remove demo tests from test folder --- test/test_hqmtool_demos.jl | 29 ----------------------------- 1 file changed, 29 deletions(-) delete mode 100644 test/test_hqmtool_demos.jl diff --git a/test/test_hqmtool_demos.jl b/test/test_hqmtool_demos.jl deleted file mode 100644 index 133a925b..00000000 --- a/test/test_hqmtool_demos.jl +++ /dev/null @@ -1,29 +0,0 @@ -module TestDemos -#= - Tests for the available demos - -Functions: @ = tested - @ hqmtool_all_features_demo(folder::String) - @ hqmtool_ice_cream_cone_verbose_demo(folder::String) - @ hqmtool_ice_cream_cone_demo(folder::String) -=# -using HOHQMesh -using Test - -# We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie is needed -# because the demos call the visualization routines. -using CairoMakie - -@testset "Demo Tests" begin - - projectPath = "out" - - @test_nowarn run_demo( projectPath, called_by_user=false ) - - @test_nowarn ice_cream_cone_verbose_demo( projectPath, called_by_user=false ) - - @test_nowarn ice_cream_cone_demo( projectPath, called_by_user=false ) - -end - -end # module \ No newline at end of file From 5eb27e69c0fde9dce4f7eeddf7f15c27662aff30 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 16 Apr 2022 21:46:01 +0200 Subject: [PATCH 141/164] small patch to throw an error in new chain creation --- src/Project/ModelAPI.jl | 19 +++++++++++++------ test/test_model.jl | 4 ++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index f1c64690..08e759e9 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -16,9 +16,10 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) insertOuterBoundaryCurveAtIndex!(proj,crv,i) enableUndo() - registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Curve") + registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Outer Boundary Curve") end + """ removeOuterBoundaryCurveWithName!(proj::Project, name::String) @@ -206,7 +207,7 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) end -function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, +function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int, boundaryName::String) i, chain = getInnerBoundaryChainWithName(proj,boundaryName) lst = chain["LIST"] @@ -220,7 +221,7 @@ function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, innerBoundaryPoints = proj.innerBoundaryPoints[i] insert!(innerBoundaryPoints,indx,curvePoints(crv,defaultPlotPts)) end - insert!(proj.innerBoundaryNames[i],indx,crv["name"]) + insert!(proj.innerBoundaryNames[i],indx,crv["name"]) proj.backgroundGridShouldUpdate = true postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) @@ -410,6 +411,7 @@ function innerBoundaryIndices(proj::Project, curveName::String) end return (0,0) end + #= CHAIN OPERATIONS =# @@ -418,7 +420,7 @@ function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{Strin See if the endpoints of crv match up to any of the curves in the chainList. If so, return the index where crv should be inserted into the list. =# - + if isempty(chainList) return 1 # Make crv the start of the chain. end @@ -426,6 +428,11 @@ function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{Strin nCurves = length(chainList) if curvesMeet(chainList[nCurves],crv) return nCurves+1 # Check first in likely case that user inputs in order + else + lastName = getCurveName(chainList[nCurves]) + newName = getCurveName(crv) + error("The curve $lastName does not meet the previous curve, $newName. Try again.") + return end # # Search though list of curves to see if the start of crv matches @@ -437,10 +444,10 @@ function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{Strin return i+1 # Add after the curve that matches. end end - + return nCurves+1 # No match, so just append to the list end - + #= OTHER =# diff --git a/test/test_model.jl b/test/test_model.jl index 80a87fc8..8677f820 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -132,14 +132,14 @@ using Test # Failing outer boundary add!(p, obc1) - @test_logs (:warn, "The curve obc1 does not meet the previous curve, obc2. Try again.") add!(p, obc2) + @test_throws ErrorException add!(p, obc2) # Failing inner boundary line = newEndPointsLineCurve("line", [0.0,-2.0,0.0], [1.0,0.0,0.0]) halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.5, 0.0, 180.0, "degrees") addCurveToInnerBoundary!(p, line, "failCurve") - @test_logs (:warn, "The curve line does not meet the previous curve, halfCircle. Try again.") add!(p, halfCircle , "failCurve") + @test_throws ErrorException add!(p, halfCircle , "failCurve") end From 839d7c7a52bd820edca4fe3674efbecbd08f06c9 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 16 Apr 2022 22:21:16 +0200 Subject: [PATCH 142/164] fix new error to be more general --- src/Project/ModelAPI.jl | 57 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 08e759e9..7e6d6bef 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -416,37 +416,36 @@ end CHAIN OPERATIONS =# function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{String, Any}}) - #= - See if the endpoints of crv match up to any of the curves in the chainList. If so, - return the index where crv should be inserted into the list. - =# - - if isempty(chainList) - return 1 # Make crv the start of the chain. - end - # - nCurves = length(chainList) - if curvesMeet(chainList[nCurves],crv) - return nCurves+1 # Check first in likely case that user inputs in order - else - lastName = getCurveName(chainList[nCurves]) - newName = getCurveName(crv) - error("The curve $lastName does not meet the previous curve, $newName. Try again.") - return - end - # - # Search though list of curves to see if the start of crv matches - # the end of one of the curves already in the chain. Linear search because - # it's easy and likely the list will not be that large. - # - for i in 1:nCurves - if curvesMeet(chainList[i],crv) - return i+1 # Add after the curve that matches. - end +# +# See if the endpoints of crv match up to any of the curves in the chainList. If so, +# return the index where crv should be inserted into the list. +# + if isempty(chainList) + return 1 # Make crv the start of the chain. + end +# + nCurves = length(chainList) + if curvesMeet(chainList[nCurves],crv) + return nCurves+1 # Check first in likely case that user inputs in order + end +# +# Search though list of curves to see if the start of crv matches +# the end of one of the curves already in the chain. Linear search because +# it's easy and likely the list will not be that large. +# + for i in 1:nCurves + if curvesMeet(chainList[i],crv) + return i+1 # Add after the curve that matches. end - - return nCurves+1 # No match, so just append to the list end + println(chainList) +# +# No match, so throw an error +# + newName = getCurveName(crv) + error("The curve $newName does does connect to any curve in the chain. Try again") + return +end #= OTHER From 0d6eafdcdfa4d94a7a3bcd47075abc89ea47a125 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 16 Apr 2022 22:45:37 +0200 Subject: [PATCH 143/164] add a few tests for new interactive example files; replacing the functions --- docs/src/HQMTool.md | 119 ++++++++++++++----------- examples/interactive_outer_boundary.jl | 56 ++++++++++++ src/HOHQMesh.jl | 86 +++++++++--------- test/runtests.jl | 3 + test/test_examples.jl | 22 +++++ 5 files changed, 190 insertions(+), 96 deletions(-) create mode 100644 examples/interactive_outer_boundary.jl create mode 100644 test/test_examples.jl diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md index 1d8bcd47..062a92cb 100644 --- a/docs/src/HQMTool.md +++ b/docs/src/HQMTool.md @@ -24,62 +24,75 @@ HQMTool is an API to generate a quad (Future:Hex) mesh using Julia. It serves as ## Introduction -HQMTool is an API to build quad/hex meshes. Three examples are included to get you started. -The first reads in an existing control file from the HOHQMesh examples collection. -To see that example, run -``` - run_demo("out") +HQMTool is an API to build quad/hex meshes. Several examples are available in the `examples` folder +to get you started. These example scripts follow the naming convention of `interactive_*` where +the phrase interactive indicates their association with HQMTool and then trailing information +will indicate what that interactive demonstrates. For instance, the file `interactive_splines.jl` +provides an interactive project that creates an manipulates splines for the inner boundaries before +generating the mesh. + +Below we highlight three fundamental scripts that demonstrate the functionality of HQMTool. More in depth +explanations of the functionality is provided in the tutuorials TODO: ADD LINK + +First is a basic example script that reads in an existing control file from the HOHQMesh examples collection. +To run that example, execute +```julia + include("interactive_from_control_file.jl") ``` -where `"out"` specifies the folder where the resulting mesh and TecPlot files will be saved. +This command will create mesh and plot files in the `out` directory. -The second example builds a new project consisting of an outer, circular boundary, and an inner -boundary in the shape of an ice cream cone. The "verbose" version of the script is given below. +The second example `interactive_outer_boundary.jl` builds a new project consisting of an outer, +circular boundary, and an inner boundary in the shape of an ice cream cone. +The "verbose" example script, where all functions arevalled with their full name, is given below. ```julia - function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) - # - # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, - # written to `folder`. The keyword arguement `called_by_user` is there for testing purposes. - # - p = newProject("IceCreamCone", folder) - # - # Outer boundary - # - circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") - addCurveToOuterBoundary!(p, circ) - # - # Inner boundary - # - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p, cone1, "IceCreamCone") - addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") - addCurveToInnerBoundary!(p, cone2, "IceCreamCone") - # - # Set some control RunParameters to overwrite the defaults - # - setPolynomialOrder!(p, 4) - setPlotFileFormat!(p, "sem") - # - # To mesh, a background grid is needed - # - addBackgroundGrid!(p, [0.5,0.5,0.0]) - - if called_by_user - # - # Show the model and grid - # - plotProject!(p, MODEL+GRID) - println("Press enter to continue and generate the mesh") - readline() - end - # - # Generate the mesh and plot - # - generate_mesh(p) - - return p - end +using HOHQMesh + +# Create a new project with the name "IceCreamCone", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. + +p = newProject("IceCreamCone", "out") + +# Outer boundary for this example mesh is a complete circle. Add it into the project. + +circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") +addCurveToOuterBoundary!(p, circ) + +# Inner boundary is three curves. Two straight lines and a circular arc. +# Note the three curve are connected to ensure a counter-clockwise orientation +# as required by HOHQMesh + +cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) +iceCream = newCircularArcCurve("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") +cone2 = newEndPointsLineCurve("cone2", [-1.0, 0.0, 0.0], [0.0, -3.0, 0.0]) +addCurveToInnerBoundary!(p, cone1, "IceCreamCone") +addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") +addCurveToInnerBoundary!(p, cone2, "IceCreamCone") + +# Adjust some `RunParameters` and overwrite the defaults values. In this case, we +# set a new value for the boundary order polynomial representation and adjust the +# output mesh file format to be `sem` + +setPolynomialOrder!(p, 4) +setPlotFileFormat!(p, "sem") + +# A background grid is required for the mesh generation. In this example we lay a +# background grid of Cartesian boxes with size 0.5. + +addBackgroundGrid!(p, [0.5, 0.5, 0.0]) + +# To plot the project model curves and the background grid, type `using GLMakie` +# in the REPL session, uncomment this line, and rerun this script + +# plotProject!(p, MODEL+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL ``` The first line creates a new project, where the mesh and plot file names will be derived from the project name, "IceCreamCone" written to the specified folder. diff --git a/examples/interactive_outer_boundary.jl b/examples/interactive_outer_boundary.jl new file mode 100644 index 00000000..f07b848d --- /dev/null +++ b/examples/interactive_outer_boundary.jl @@ -0,0 +1,56 @@ +# Interactive mesh with an outer boundary constructed by a user +# +# Create a circular outer boundary and an inner ice cream cone shaped boundary +# consisting of three curves, lay a background grid and generate a HOHQMesh +# directly from the project object. +# +# Keywords: outer boundary chain, inner boundary chain, verbose commands + +using HOHQMesh + +# Create a new project with the name "IceCreamCone", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. + +p = newProject("IceCreamCone", "out") + +# Outer boundary for this example mesh is a complete circle. Add it into the project. + +circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") +addCurveToOuterBoundary!(p, circ) + +# Inner boundary is three curves. Two straight lines and a circular arc. +# Note the three curve are connected to ensure a counter-clockwise orientation +# as required by HOHQMesh + +cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) +iceCream = newCircularArcCurve("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") +cone2 = newEndPointsLineCurve("cone2", [-1.0, 0.0, 0.0], [0.0, -3.0, 0.0]) +addCurveToInnerBoundary!(p, cone1, "IceCreamCone") +addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") +addCurveToInnerBoundary!(p, cone2, "IceCreamCone") + +# Adjust some `RunParameters` and overwrite the defaults values. In this case, we +# set a new value for the boundary order polynomial representation and adjust the +# output mesh file format to be `sem` + +setPolynomialOrder!(p, 4) +setPlotFileFormat!(p, "sem") + +# A background grid is required for the mesh generation. In this example we lay a +# background grid of Cartesian boxes with size 0.5. + +addBackgroundGrid!(p, [0.5, 0.5, 0.0]) + +# To plot the project model curves and the background grid, type `using GLMakie` +# in the REPL session, uncomment this line, and rerun this script + +# plotProject!(p, MODEL+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL \ No newline at end of file diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 6bdb20f7..5b299140 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -360,50 +360,50 @@ include("Mesh/Meshing.jl") # end -function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) -# -# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# written to `folder`. -# - p = newProject("IceCreamCone", folder) -# -# Outer boundary -# - circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") - addCurveToOuterBoundary!(p, circ) -# -# Inner boundary -# - cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) - iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") - cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) - addCurveToInnerBoundary!(p, cone1, "IceCreamCone") - addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") - addCurveToInnerBoundary!(p, cone2, "IceCreamCone") -# -# Set some control RunParameters to overwrite the defaults -# - setPolynomialOrder!(p, 4) - setPlotFileFormat!(p, "sem") -# -# To mesh, a background grid is needed -# - addBackgroundGrid!(p, [0.5,0.5,0.0]) -# -# Show the model and grid -# - plotProject!(p, MODEL+GRID) - println("Press enter to continue and generate the mesh") - if called_by_user - readline() - end -# -# Generate the mesh and plot -# - generate_mesh(p) +# function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) +# # +# # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, +# # written to `folder`. +# # +# p = newProject("IceCreamCone", folder) +# # +# # Outer boundary +# # +# circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") +# addCurveToOuterBoundary!(p, circ) +# # +# # Inner boundary +# # +# cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) +# iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") +# cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) +# addCurveToInnerBoundary!(p, cone1, "IceCreamCone") +# addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") +# addCurveToInnerBoundary!(p, cone2, "IceCreamCone") +# # +# # Set some control RunParameters to overwrite the defaults +# # +# setPolynomialOrder!(p, 4) +# setPlotFileFormat!(p, "sem") +# # +# # To mesh, a background grid is needed +# # +# addBackgroundGrid!(p, [0.5,0.5,0.0]) +# # +# # Show the model and grid +# # +# plotProject!(p, MODEL+GRID) +# println("Press enter to continue and generate the mesh") +# if called_by_user +# readline() +# end +# # +# # Generate the mesh and plot +# # +# generate_mesh(p) - return p -end +# return p +# end function ice_cream_cone_demo(folder::String; called_by_user=true) diff --git a/test/runtests.jl b/test/runtests.jl index 4c13417a..892f4647 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -68,6 +68,9 @@ include("test_model.jl") # HQMTool project test routines include("test_hqmtool_project.jl") +# HQMTool interactive examples available in examples folder +include("test_examples.jl") + # HQMTool project + visualzation test routines include("test_project_with_viz.jl") diff --git a/test/test_examples.jl b/test/test_examples.jl new file mode 100644 index 00000000..5eb77498 --- /dev/null +++ b/test/test_examples.jl @@ -0,0 +1,22 @@ +module TestInteractiveExamples + +using HOHQMesh +using Test + +# We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used +# as a testing backend for HQMTool's Makie-based visualization. +#using CairoMakie + +@testset "Interactive Examples Tests" begin + + test_file = joinpath(examples_dir(), "interactive_from_control_file.jl") + include(test_file) + @test p.name == "AllFeatures" + + test_file = joinpath(examples_dir(), "interactive_outer_boundary.jl") + include(test_file) + @test p.name == "IceCreamCone" + +end + +end #module \ No newline at end of file From b292b6dbc25dd8fd6468e142c031275dc5dfbcef Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Sat, 16 Apr 2022 23:31:58 +0200 Subject: [PATCH 144/164] adjust test for new strategy of adding curves in arbitrary order --- src/Project/ModelAPI.jl | 9 ++------- test/test_model.jl | 15 +++++++-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index 7e6d6bef..af97df91 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -438,13 +438,8 @@ function chainInsertionIndex(crv::Dict{String,Any}, chainList::Vector{Dict{Strin return i+1 # Add after the curve that matches. end end - println(chainList) -# -# No match, so throw an error -# - newName = getCurveName(crv) - error("The curve $newName does does connect to any curve in the chain. Try again") - return + + return nCurves+1 # No match, so just append to the list end #= diff --git a/test/test_model.jl b/test/test_model.jl index 8677f820..855f4721 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -125,21 +125,20 @@ using Test # # Purposely create outer / inner boundary curves that do not join in a new project. -# Triggers appropriate warning statements. +# Attempt to generate a mesh and trigger an appropriate warning statement. # obc1 = new("obc1",[0.0,0.0,0.0], [2.0,0.0,0.0]) obc2 = new("obc2",[3.0,0.0,0.0], [1.0,1.0,0.0]) + # A background grid is required for the mesh generation call + addBackgroundGrid!(p, [0.5, 0.5, 0.0]) + # Failing outer boundary add!(p, obc1) - @test_throws ErrorException add!(p, obc2) - - # Failing inner boundary - line = newEndPointsLineCurve("line", [0.0,-2.0,0.0], [1.0,0.0,0.0]) - halfCircle = newCircularArcCurve("halfCircle", [0.0,0.0,0.0], 1.5, 0.0, 180.0, "degrees") + add!(p, obc2) - addCurveToInnerBoundary!(p, line, "failCurve") - @test_throws ErrorException add!(p, halfCircle , "failCurve") + # This call actually throws multiple warnings but we just test that the main one is thrown + @test_logs (:warn, "Meshing aborted: Ensure boundary curve segments are in order and boundary curves are closed and try again.") match_mode=:any generate_mesh(p) end From 51dacf84a1021e2de7b80bd8a085b9b4f3fcf0c6 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 20 Apr 2022 22:28:03 +0200 Subject: [PATCH 145/164] automatically update the file names if the mesh format changes --- src/Project/RunParametersAPI.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Project/RunParametersAPI.jl b/src/Project/RunParametersAPI.jl index f5d4e5fd..862c82fa 100644 --- a/src/Project/RunParametersAPI.jl +++ b/src/Project/RunParametersAPI.jl @@ -12,7 +12,6 @@ function addRunParameters!(proj::Project, meshFileFormat::String = "ISM-V2", polynomialOrder::Int = 5) - setFileNames!(proj, meshFileFormat) setPlotFileFormat!(proj, plotFormat) setMeshFileFormat!(proj, meshFileFormat) setPolynomialOrder!(proj, polynomialOrder) @@ -43,7 +42,7 @@ end The `name` of the project is the filename to be used by the mesh, plot, and stats files. It is also the name of the control file the tool will produce. """ -function setName!(proj::Project,name::String) +function setName!(proj::Project, name::String) oldName = proj.name registerWithUndoManager(proj,setName!,(oldName,),"Set Project Name") @@ -108,6 +107,9 @@ function setMeshFileFormat!(proj::Project, meshFileFormat::String) registerWithUndoManager(proj,setMeshFileFormat!,(oldFormat,),"Set Mesh Format") end rpDict[key] = meshFileFormat + + # Set the appropriate file names and extensions from the given `meshFileFormat` + setFileNames!(proj, meshFileFormat) end From b236f5c27b620a998a2d9695e4f858f6b415d232 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 09:54:06 +0200 Subject: [PATCH 146/164] bug fix in model curves check. --- src/Project/Project.jl | 44 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index e5866228..010f6c21 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -371,10 +371,6 @@ function refinementDidChange(proj::Project, sender::Dict{String,Any}) end updatePlot!(proj, options) end - # TODO: Remove this? It triggers to the screen frequently during example that work - # correctly. Not sure why it is here. - # else - # println("Refinement region with name $regionName not found.") end end @@ -400,31 +396,45 @@ function meshWasDeleted(proj::Project, sender::Project) end end + """ modelCurvesAreOK(proj::Project) -Go through all curves in the model and make sure they are connected and closed. +Go through all curves in the model and make sure they are connected and closed. +Also, remove any empty outer / inner boundary chains. Returns true if all curves are connected and closed, false otherwise. """ function modelCurvesAreOK(proj::Project) result = true - - chain = getOuterBoundaryChainList(proj) - if !isempty(chain) - result = modelChainIsOK(chain,"Outer") + if !haskey(proj.projectDictionary,"MODEL") + return true end - - innerBoundariesList = getAllInnerBoundaries(proj) - - for chain in innerBoundariesList - chainName = string(chain["name"]) - chainList = chain["LIST"] - result = result && modelChainIsOK(chainList,chainName) + modelDict = getModelDict(proj) + if haskey(modelDict,"OUTER_BOUNDARY") + chain = getOuterBoundaryChainList(proj) + if !isempty(chain) + result = modelChainIsOK(chain,"Outer") + else + delete!(modelDict,"OUTER_BOUNDARY") + end + end + if haskey(modelDict,"INNER_BOUNDARIES") + innerBoundariesList = getAllInnerBoundaries(proj) + if isempty(innerBoundariesList) + delete!(modelDict,"INNER_BOUNDARIES") + return result + end + for chain in innerBoundariesList + chainName = string(chain["name"]) + chainList = chain["LIST"] + result = result && modelChainIsOK(chainList,chainName) + end end - return result end + + """ modelChainIsOK(chain::Vector{Dict{String, Any}}, chainName::String) From c83e86d91aca0b6fe859212a9c8d5030324207e0 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 20:20:34 +0200 Subject: [PATCH 147/164] improve comments in ice cream cone example file --- examples/interactive_outer_boundary.jl | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/interactive_outer_boundary.jl b/examples/interactive_outer_boundary.jl index f07b848d..e077b4a7 100644 --- a/examples/interactive_outer_boundary.jl +++ b/examples/interactive_outer_boundary.jl @@ -1,10 +1,10 @@ # Interactive mesh with an outer boundary constructed by a user # # Create a circular outer boundary and an inner ice cream cone shaped boundary -# consisting of three curves, lay a background grid and generate a HOHQMesh +# chain consisting of three curves, lay a background grid and generate a HOHQMesh # directly from the project object. # -# Keywords: outer boundary chain, inner boundary chain, verbose commands +# Keywords: outer boundary chain, inner boundary chain using HOHQMesh @@ -22,16 +22,24 @@ addCurveToOuterBoundary!(p, circ) # Note the three curve are connected to ensure a counter-clockwise orientation # as required by HOHQMesh +# Create the three interior curves. The individual names of each curve in the inner +# chain are used internally by HOHQMesh and are output as the given boundary names in +# the mesh file. + cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) iceCream = newCircularArcCurve("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") cone2 = newEndPointsLineCurve("cone2", [-1.0, 0.0, 0.0], [0.0, -3.0, 0.0]) + +# Assemble the three curve in a closed chain oriented couter-clockwise. The chain +# name `IceCreamCone` is only used internally by HOHQMesh. + addCurveToInnerBoundary!(p, cone1, "IceCreamCone") addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") addCurveToInnerBoundary!(p, cone2, "IceCreamCone") # Adjust some `RunParameters` and overwrite the defaults values. In this case, we # set a new value for the boundary order polynomial representation and adjust the -# output mesh file format to be `sem` +# output plot file format to be `sem` setPolynomialOrder!(p, 4) setPlotFileFormat!(p, "sem") @@ -46,11 +54,11 @@ addBackgroundGrid!(p, [0.5, 0.5, 0.0]) # plotProject!(p, MODEL+GRID) -# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` -# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# Generate the mesh. This produces the mesh and TecPlot files `IceCreamCone.mesh` and `IceCreamCone.tec` +# and saves them to the `out` folder. Also, if there is an active plot in the project `p` it is # updated with the mesh that was generated. generate_mesh(p) # After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, -# the number of elements etc., are printed to the REPL \ No newline at end of file +# the number of elements etc., are printed to the REPL. \ No newline at end of file From f6ef83f27ee687d155c403c074d7ae3616128a94 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 20:34:53 +0200 Subject: [PATCH 148/164] move demos out of library and into example files --- examples/interactive_from_control_file.jl | 2 +- .../interactive_outer_boundary_generic.jl | 61 +++++++++ src/HOHQMesh.jl | 119 ------------------ test/test_examples.jl | 7 ++ 4 files changed, 69 insertions(+), 120 deletions(-) create mode 100644 examples/interactive_outer_boundary_generic.jl diff --git a/examples/interactive_from_control_file.jl b/examples/interactive_from_control_file.jl index 7ae03e54..85df84e2 100644 --- a/examples/interactive_from_control_file.jl +++ b/examples/interactive_from_control_file.jl @@ -31,4 +31,4 @@ p = openProject(all_features_control_file, "out") generate_mesh(p) # After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, -# the number of elements etc., are printed to the REPL \ No newline at end of file +# the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/interactive_outer_boundary_generic.jl b/examples/interactive_outer_boundary_generic.jl new file mode 100644 index 00000000..da94c9e4 --- /dev/null +++ b/examples/interactive_outer_boundary_generic.jl @@ -0,0 +1,61 @@ +# Interactive mesh with an outer boundary constructed by a user +# using generic function calls +# +# Create a circular outer boundary and an inner ice cream cone shaped boundary +# chain consisting of three curves, lay a background grid and generate a HOHQMesh +# directly from the project object. +# +# In particular, this example highligths available generic functionality for creating +# and adding new curves to a project. +# +# Keywords: outer boundary chain, inner boundary chain, generic functions + +using HOHQMesh + +# Create a new project with the name "IceCreamCone", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. + +p = newProject("IceCreamCone", "out") + +# Outer boundary for this example mesh is a complete circle. Add it into the project. + +circ = new("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 2.0 * pi, "radians") +add!(p, circ) + +# Inner boundary is three curves. Two straight lines and a circular arc. +# Note the three curve are connected to ensure a counter-clockwise orientation +# as required by HOHQMesh + +# Create the three interior curves. The individual names of each curve in the inner +# chain are used internally by HOHQMesh and are output as the given boundary names in +# the mesh file. + +cone1 = new("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) +iceCream = new("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") +cone2 = new("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) + +# Assemble the three curve in a closed chain oriented couter-clockwise. The chain +# name `IceCreamCone` is only used internally by HOHQMesh. + +add!(p, cone1, "IceCreamCone") +add!(p, iceCream, "IceCreamCone") +add!(p, cone2, "IceCreamCone") + +# A background grid is required for the mesh generation. In this example we lay a +# background grid of Cartesian boxes with size 0.5. + +addBackgroundGrid!(p, [0.5,0.5,0.0]) + +# To plot the project model curves and the background grid, type `using GLMakie` +# in the REPL session, uncomment this line, and rerun this script + +# plotProject!(p, MODEL+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 5b299140..7b649ec6 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -25,10 +25,6 @@ export generate_mesh # Make the examples directory available to the user export examples_dir -# Functions useful to demonstrate the interactive HQMTool -#export run_demo, ice_cream_cone_verbose_demo, ice_cream_cone_demo -export ice_cream_cone_verbose_demo, ice_cream_cone_demo - # Generic functions for the HQMTool interface export new, add!, @@ -338,119 +334,4 @@ include("Project/SmootherAPI.jl") # Main routine that uses HOHQMesh to generate a mesh from an interactive `Project` include("Mesh/Meshing.jl") -# -#---------------- Routines for demonstrating the HQMTool --------------------------------- -# - -# function run_demo(folder::String; called_by_user=true) -# # -# # Reads in an existing control file, plots the boundary curves and generates -# # a mesh. -# # -# all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) -# p = openProject(all_features_control_file, folder) - -# plotProject!(p, MODEL+REFINEMENTS+GRID) -# println("Press enter to continue and generate the mesh") -# if called_by_user -# readline() -# end -# generate_mesh(p) -# return p -# end - - -# function ice_cream_cone_verbose_demo(folder::String; called_by_user=true) -# # -# # Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# # written to `folder`. -# # -# p = newProject("IceCreamCone", folder) -# # -# # Outer boundary -# # -# circ = newCircularArcCurve("outerCircle", [0.0,-1.0,0.0], 4.0, 0.0, 360.0, "degrees") -# addCurveToOuterBoundary!(p, circ) -# # -# # Inner boundary -# # -# cone1 = newEndPointsLineCurve("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) -# iceCream = newCircularArcCurve("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") -# cone2 = newEndPointsLineCurve("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) -# addCurveToInnerBoundary!(p, cone1, "IceCreamCone") -# addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") -# addCurveToInnerBoundary!(p, cone2, "IceCreamCone") -# # -# # Set some control RunParameters to overwrite the defaults -# # -# setPolynomialOrder!(p, 4) -# setPlotFileFormat!(p, "sem") -# # -# # To mesh, a background grid is needed -# # -# addBackgroundGrid!(p, [0.5,0.5,0.0]) -# # -# # Show the model and grid -# # -# plotProject!(p, MODEL+GRID) -# println("Press enter to continue and generate the mesh") -# if called_by_user -# readline() -# end -# # -# # Generate the mesh and plot -# # -# generate_mesh(p) - -# return p -# end - - -function ice_cream_cone_demo(folder::String; called_by_user=true) -# -# Create a project with the name "IceCreamCone", which will be the name of the mesh, plot and stats files, -# written to `path`. -# - p = newProject("IceCreamCone", folder) -# -# Outer boundary -# - circ = new("outerCircle", [0.0,-1.0,0.0],4.0,0.0,360.0,"degrees") - add!(p,circ) -# -# Inner boundary -# - cone1 = new("cone1", [0.0,-3.0,0.0], [1.0,0.0,0.0]) - iceCream = new("iceCream", [0.0,0.0,0.0], 1.0, 0.0, 180.0, "degrees") - cone2 = new("cone2", [-1.0,0.0,0.0], [0.0,-3.0,0.0]) - add!(p, cone1, "IceCreamCone") - add!(p, iceCream, "IceCreamCone") - add!(p, cone2, "IceCreamCone") -# -# To mesh, a background grid is needed -# - addBackgroundGrid!(p, [0.5,0.5,0.0]) -# -# Set alternative file format and corresponding output file names -# - setMeshFileFormat!(p, "ABAQUS") - meshFileFormat = getMeshFileFormat(p) - setFileNames!(p, meshFileFormat) -# -# Show the model and grid -# - plotProject!(p, MODEL+GRID) - println("Press enter to continue and generate the mesh") - if called_by_user - readline() - end -# -# Generate the mesh and plot -# - generate_mesh(p) - - return p -end - - end # module diff --git a/test/test_examples.jl b/test/test_examples.jl index 5eb77498..b9a64d2c 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -17,6 +17,13 @@ using Test include(test_file) @test p.name == "IceCreamCone" + test_file = joinpath(examples_dir(), "interactive_outer_boundary_generic.jl") + include(test_file) + N = getPolynomialOrder(p) + println(N) + # Test against the default polynomial order of 5 that gets reset in this include + @test N == 5 + end end #module \ No newline at end of file From b72a013b078c6132d949a4a7e3c7fc88effbc517 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 21:09:04 +0200 Subject: [PATCH 149/164] add new example file with staight-sided outer boundary --- examples/interactive_outer_box_two_circles.jl | 66 +++++++++++++++++++ test/test_examples.jl | 7 +- 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 examples/interactive_outer_box_two_circles.jl diff --git a/examples/interactive_outer_box_two_circles.jl b/examples/interactive_outer_box_two_circles.jl new file mode 100644 index 00000000..5f974f02 --- /dev/null +++ b/examples/interactive_outer_box_two_circles.jl @@ -0,0 +1,66 @@ +# Interactive mesh with a rectangular outer boundary and two circular inner boundaries +# +# TODO +# +# Keywords: TODO + +using HOHQMesh + +# TODO: Comment here + +p = newProject("box_two_circles", "out") + +# Adjust some `RunParameters` and overwrite the defaults values. In this case, we +# set a new value for the boundary order polynomial representation and adjust the +# output mesh file format to be `ABAQUS`, which will produce a mesh file `outer_box.inp` + +setPolynomialOrder!(p, 4) +setMeshFileFormat!(p, "ABAQUS") + +# Outer boundary for this example mesh wil be a rectangular box. For this the user +# can set the lower left most point of the box, the spacing size in each coordinate +# direction `[Δx, Δy, Δz]`, and the number of intervals taken. + +lower_left = [0.0, 0.0, 0.0] +spacing = [1.0, 1.0, 0.0] +num_intervals = [30, 15, 0] + +# These three quanties can set the background grid that is required by HOHQMesh for a given domain. + +addBackgroundGrid!(p, lower_left, spacing, num_intervals) + +# Inner boundaries for this example will be two circles with different radii. + +# A circle with radius 2.0, centered at [4.0, 4.0, 0.0]. Note, we use degrees to set the angle. +# This inner boundary curve name will be written to the mesh file. + +circle1 = newCircularArcCurve("circle1", [4.0, 4.0, 0.0], 2.0, 0.0, 360.0, "degrees") + +# Add `circle1` into the project as an inner boundary +# This chian name in only used internally by HOHQMesh. + +addCurveToInnerBoundary!(p, circle1, "inner1") + +# A circle with radius 4.0, centered at [20.0, 9.0, 0.0]. Note, the user can use radians to set the angle. +# This inner boundary curve name will be written to the mesh file. + +circle2 = newCircularArcCurve("circle2", [20.0, 9.0, 0.0], 4.0, 0.0, 2.0 * pi, "radians") + +# Add `circle2` into the project as an inner boundary +# This chian name in only used internally by HOHQMesh. + +addCurveToInnerBoundary!(p, circle2, "inner2") + +# To plot the project model curves and the background grid, type `using GLMakie` +# in the REPL session, uncomment this line, and rerun this script + +# plotProject!(p, MODEL+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/test/test_examples.jl b/test/test_examples.jl index b9a64d2c..da86a108 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -20,10 +20,15 @@ using Test test_file = joinpath(examples_dir(), "interactive_outer_boundary_generic.jl") include(test_file) N = getPolynomialOrder(p) - println(N) # Test against the default polynomial order of 5 that gets reset in this include @test N == 5 + test_file = joinpath(examples_dir(), "interactive_outer_box_two_circles.jl") + include(test_file) + format = getMeshFileFormat(p) + # Test against the mesh file format type for this example + @test format == "ABAQUS" + end end #module \ No newline at end of file From 79999ea00f045ebed4f2aed0fff182170a0dab71 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 21:12:07 +0200 Subject: [PATCH 150/164] update header of new two circle example --- examples/interactive_outer_box_two_circles.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/interactive_outer_box_two_circles.jl b/examples/interactive_outer_box_two_circles.jl index 5f974f02..4905430d 100644 --- a/examples/interactive_outer_box_two_circles.jl +++ b/examples/interactive_outer_box_two_circles.jl @@ -1,8 +1,9 @@ # Interactive mesh with a rectangular outer boundary and two circular inner boundaries # -# TODO +# Create a domain with two circular inner boundaries and a rectangular outer boundary +# that is straight-sided. Set the output mesh file format to be ABAQUS. # -# Keywords: TODO +# Keywords: Straight-sided outer boundary, inner boundary chain, ABAQUS file format using HOHQMesh From 955dc20a230d96ab9c51af9a6e8865c30d5d88cb Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 22:28:00 +0200 Subject: [PATCH 151/164] add another example file with splines --- examples/interactive_spline_curves.jl | 82 +++++++++++++++++++++++++++ test/test_examples.jl | 6 ++ 2 files changed, 88 insertions(+) create mode 100644 examples/interactive_spline_curves.jl diff --git a/examples/interactive_spline_curves.jl b/examples/interactive_spline_curves.jl new file mode 100644 index 00000000..24f21e2c --- /dev/null +++ b/examples/interactive_spline_curves.jl @@ -0,0 +1,82 @@ +# Interactive mesh with spline curves +# +# Create a mesh with a circular outer boundary and three inner boundaries. +# Two inner boundaries are parametric splines, on econstructred from file data and +# the other from given data points. The third curve is a triangular object built from +# three internal straight-sided "curves". +# +# Keywords: spline from file, spline construction, outer boundary, inner boundary + +projectName = "spline_boundary" +projectPath = "out" + +# Create a new project with the name "spline_boundary", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. + +p = newProject(projectName, projectPath) + +# A background grid is required for the mesh generation. In this example we lay a +# background grid of Cartesian boxes with size 0.6 in each direction. + +addBackgroundGrid!(p, [0.6, 0.6, 0.0]) + +# Outer boundary for this example mesh is a complete circle. Add it into the project. + +circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") +addCurveToOuterBoundary!(p, circ) + +# Inner boundaries will have three curves: +# (i) Cubic spline curve created from data pooints read in from a file. +# (ii) Cubic spline curve created from points directly given in the code. +# (iii) Triangle shape built from three staight line "curves". + +# Create the three interior curves. The curve name are those that are output as the +# given boundary names in the mesh file. + +# First inner boundary is a parametric cubic spline read in from a file. Note, for convenience, +# we reuse a spline from the testing routines. For information on formatting cubic spline data +# files see the HOHQMesh documentation: +# https://trixi-framework.github.io/HOHQMesh/the-model/#the-spline-curve-definition + +spline1 = newSplineCurve("big_spline", joinpath(@__DIR__, "..", "test", "test_spline_curve_data.txt")) +addCurveToInnerBoundary!(p, spline1, "inner1") + +# Second inner boundary is a parametric cubic spline with data points directly provided +# in the code. These points take the form [t, x, y, z] where `t` is the parameter variable. +# For the spline construction the number of points is included as an input argument as well as +# the actual parametric point data. + +spline_data = [ [0.0 1.75 -1.0 0.0] + [0.25 2.1 -0.5 0.0] + [0.5 2.7 -1.0 0.0] + [0.75 0.6 -2.0 0.0] + [1.0 1.75 -1.0 0.0] ] +spline2 = newSplineCurve("small_spline", 5, spline_data) +addCurveToInnerBoundary!(p, spline2, "inner2") + +# Third inner boundary is a triangular shape built from three straight lines "curves". +# The three lines are connected in a counter-clockwise orientation as required by HOHQMesh. +# Note that we give the three inner curves the same name "triangle" that will be the +# boundary name given in the mesh file. The inner boundary chain name `inner3` is used +# internally for HOHQMesh but is not known to the mesh file naming. + +edge1 = newEndPointsLineCurve("triangle", [-2.3, -1.0, 0.0], [-1.7, -1.0, 0.0]) +edge2 = newEndPointsLineCurve("triangle", [-1.7, -1.0, 0.0], [-2.0, -0.4, 0.0]) +edge3 = newEndPointsLineCurve("triangle", [-2.0, -0.4, 0.0], [-2.3, -1.0, 0.0]) +addCurveToInnerBoundary!(p, edge1, "inner3") +addCurveToInnerBoundary!(p, edge2, "inner3") +addCurveToInnerBoundary!(p, edge3, "inner3") + +# To plot the project model curves and the background grid, type `using GLMakie` +# in the REPL session, uncomment this line, and rerun this script + +# plotProject!(p, MODEL+GRID) + +# Generate the mesh. This produces the mesh and TecPlot files `IceCreamCone.mesh` and `IceCreamCone.tec` +# and saves them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/test/test_examples.jl b/test/test_examples.jl index da86a108..e6d11030 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -29,6 +29,12 @@ using Test # Test against the mesh file format type for this example @test format == "ABAQUS" + test_file = joinpath(examples_dir(), "interactive_spline_curves.jl") + include(test_file) + spline = getCurve(p, "big_spline", "inner1") + # Test against the number of spline knots from the testing file + @test spline["nKnots"] == "77" + end end #module \ No newline at end of file From 08968d9ea2cf4de5800e680a44d39d202018390f Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 22 Apr 2022 22:29:15 +0200 Subject: [PATCH 152/164] better spacing --- examples/interactive_spline_curves.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/interactive_spline_curves.jl b/examples/interactive_spline_curves.jl index 24f21e2c..42590a66 100644 --- a/examples/interactive_spline_curves.jl +++ b/examples/interactive_spline_curves.jl @@ -51,6 +51,7 @@ spline_data = [ [0.0 1.75 -1.0 0.0] [0.5 2.7 -1.0 0.0] [0.75 0.6 -2.0 0.0] [1.0 1.75 -1.0 0.0] ] + spline2 = newSplineCurve("small_spline", 5, spline_data) addCurveToInnerBoundary!(p, spline2, "inner2") From 96254d3cb83a9253992a83b0a44cd7d05e1fb8f8 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Apr 2022 18:57:00 +0200 Subject: [PATCH 153/164] add proper plotting logic and output statements for the user --- examples/interactive_from_control_file.jl | 13 +++++++++---- examples/interactive_outer_boundary.jl | 13 +++++++++---- examples/interactive_outer_boundary_generic.jl | 12 +++++++++--- examples/interactive_outer_box_two_circles.jl | 13 +++++++++---- examples/interactive_spline_curves.jl | 13 +++++++++---- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/examples/interactive_from_control_file.jl b/examples/interactive_from_control_file.jl index 85df84e2..1e137f71 100644 --- a/examples/interactive_from_control_file.jl +++ b/examples/interactive_from_control_file.jl @@ -19,10 +19,15 @@ all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) p = openProject(all_features_control_file, "out") -# To plot the project, type `using GLMakie` in the REPL session, uncomment this line, and rerun -# this script - -# plotProject!(p, MODEL+REFINEMENTS+GRID) +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() + else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." + end # Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` # and save them to the `out` folder. Also, if there is an active plot in the project `p` it is diff --git a/examples/interactive_outer_boundary.jl b/examples/interactive_outer_boundary.jl index e077b4a7..abb183b8 100644 --- a/examples/interactive_outer_boundary.jl +++ b/examples/interactive_outer_boundary.jl @@ -49,10 +49,15 @@ setPlotFileFormat!(p, "sem") addBackgroundGrid!(p, [0.5, 0.5, 0.0]) -# To plot the project model curves and the background grid, type `using GLMakie` -# in the REPL session, uncomment this line, and rerun this script - -# plotProject!(p, MODEL+GRID) +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() + else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." + end # Generate the mesh. This produces the mesh and TecPlot files `IceCreamCone.mesh` and `IceCreamCone.tec` # and saves them to the `out` folder. Also, if there is an active plot in the project `p` it is diff --git a/examples/interactive_outer_boundary_generic.jl b/examples/interactive_outer_boundary_generic.jl index da94c9e4..73e9cb11 100644 --- a/examples/interactive_outer_boundary_generic.jl +++ b/examples/interactive_outer_boundary_generic.jl @@ -47,9 +47,15 @@ add!(p, cone2, "IceCreamCone") addBackgroundGrid!(p, [0.5,0.5,0.0]) # To plot the project model curves and the background grid, type `using GLMakie` -# in the REPL session, uncomment this line, and rerun this script - -# plotProject!(p, MODEL+GRID) +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() + else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." + end # Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` # and save them to the `out` folder. Also, if there is an active plot in the project `p` it is diff --git a/examples/interactive_outer_box_two_circles.jl b/examples/interactive_outer_box_two_circles.jl index 4905430d..1cb34321 100644 --- a/examples/interactive_outer_box_two_circles.jl +++ b/examples/interactive_outer_box_two_circles.jl @@ -52,10 +52,15 @@ circle2 = newCircularArcCurve("circle2", [20.0, 9.0, 0.0], 4.0, 0.0, 2.0 * pi, " addCurveToInnerBoundary!(p, circle2, "inner2") -# To plot the project model curves and the background grid, type `using GLMakie` -# in the REPL session, uncomment this line, and rerun this script - -# plotProject!(p, MODEL+GRID) +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() +else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." +end # Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` # and save them to the `out` folder. Also, if there is an active plot in the project `p` it is diff --git a/examples/interactive_spline_curves.jl b/examples/interactive_spline_curves.jl index 42590a66..bdd57af3 100644 --- a/examples/interactive_spline_curves.jl +++ b/examples/interactive_spline_curves.jl @@ -68,10 +68,15 @@ addCurveToInnerBoundary!(p, edge1, "inner3") addCurveToInnerBoundary!(p, edge2, "inner3") addCurveToInnerBoundary!(p, edge3, "inner3") -# To plot the project model curves and the background grid, type `using GLMakie` -# in the REPL session, uncomment this line, and rerun this script - -# plotProject!(p, MODEL+GRID) +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() + else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." + end # Generate the mesh. This produces the mesh and TecPlot files `IceCreamCone.mesh` and `IceCreamCone.tec` # and saves them to the `out` folder. Also, if there is an active plot in the project `p` it is From 1d2eb464f5b054f539dc49543e2e1e66e340dc5f Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Fri, 29 Apr 2022 19:00:23 +0200 Subject: [PATCH 154/164] fix comment in two circles example --- examples/interactive_outer_box_two_circles.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/interactive_outer_box_two_circles.jl b/examples/interactive_outer_box_two_circles.jl index 1cb34321..dcb47762 100644 --- a/examples/interactive_outer_box_two_circles.jl +++ b/examples/interactive_outer_box_two_circles.jl @@ -7,7 +7,8 @@ using HOHQMesh -# TODO: Comment here +# Create a new project with the name "box_two_circles", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. p = newProject("box_two_circles", "out") From d6416545c5b1d173e8631d22fd4c41ccd6c9e055 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Mon, 2 May 2022 08:17:01 +0200 Subject: [PATCH 155/164] remove unnecessary tests --- test/runtests.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 892f4647..cb99f3a9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -51,7 +51,7 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" -# Unit tests for the HQMTool functionality +# Unit tests for the HQMTool interactive functionality # Background grid test routines include("test_background_grid.jl") @@ -62,9 +62,6 @@ include("test_curve.jl") # Model test routines include("test_model.jl") -# HQMTool demonstration test routines -#include("test_hqmtool_demos.jl") - # HQMTool project test routines include("test_hqmtool_project.jl") From 9442d40334f8d7144a7847bed7755303294da216 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 15 Jun 2022 13:53:48 +0200 Subject: [PATCH 156/164] Bump compat of CairoMakie in the testing Project.toml --- test/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Project.toml b/test/Project.toml index 0a3a17e0..29ae53d8 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -5,4 +5,4 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] AbaqusReader = "0.2.5" -CairoMakie = "0.6, 0.7" \ No newline at end of file +CairoMakie = "0.6, 0.7, 0.8" \ No newline at end of file From 741fe416b10aecd9f11f35b74c980abf254986db Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Wed, 15 Jun 2022 14:30:38 +0200 Subject: [PATCH 157/164] update docstrings --- src/Project/BackgroundGridAPI.jl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 1c9f765d..89b194ef 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -57,7 +57,6 @@ backgroundGrid block, but the version is a lot easier to use. TODO: Change HOHQMesh and delete this way to specify the domain and use the bounding box one instead. - """ function addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") @@ -218,7 +217,10 @@ end """ - setBackgroundGridSize!(proj::Project, dx::Array{Float64},key::String) + setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) + +Set the grid size dx of an existing background grid withing `proj`. Here, `dx` +is passed an array. """ function setBackgroundGridSize!(proj::Project, dx::Array{Float64}, key::String) setBackgroundGridSize!(proj, dx[1], dx[2], key) @@ -227,9 +229,12 @@ end """ - setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) + setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, key::String) + +Set the grid size dx of an existing background grid withing `proj`. Here, the new grid +size in either direction is passed individually with `dx`and `dy`. """ -function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64,key::String) +function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, key::String) bgDict = getDictInControlDictNamed(proj,"BACKGROUND_GRID") if haskey(bgDict,key) From 03834ae63e660464e1257642409935917617b0f4 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 16 Jun 2022 07:32:42 +0200 Subject: [PATCH 158/164] update more docstrings --- src/Mesh/Meshing.jl | 13 +++++++++++++ src/Project/CurvesAPI.jl | 1 - src/Project/Project.jl | 4 ++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index c873db62..122960b9 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -1,4 +1,17 @@ +""" + generate_mesh(proj::Project) + +Generate a mesh based on the `proj` created using the HQMTool. First a check is made +if a background grid exists and all inner/outer boundary curves are valid. + +This function will then make a HOHQMesh control file from the control dictionary `proj.controlDict` +and use it to call the wrapper function that interfaces with HOHQMesh. The resulting mesh and control files +will be saved to `proj.projectDirectory`. Also, if there is an active plot of the mesh project it +will update to display the generated mesh. + +This function returns the output to `stdout` of the HOHQMesh binary when generating the mesh. +""" function generate_mesh(proj::Project) # # Check to be sure background grid has been created (everything else is defaults) diff --git a/src/Project/CurvesAPI.jl b/src/Project/CurvesAPI.jl index 3010ef16..a6d37aa5 100644 --- a/src/Project/CurvesAPI.jl +++ b/src/Project/CurvesAPI.jl @@ -435,7 +435,6 @@ end """ getArcRadius(arc::Dict{String,Any}, radius::Float64) - """ function getArcRadius(arc::Dict{String,Any}) return parse(Float64,arc["radius"]) diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 010f6c21..e6d6c69b 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -136,7 +136,7 @@ end """ -hasBackgroundGrid(proj::Project) + hasBackgroundGrid(proj::Project) Tests to see if the project has a backgroundGrid dictionary defined. """ @@ -436,7 +436,7 @@ end """ - modelChainIsOK(chain::Vector{Dict{String, Any}}, chainName::String) + modelChainIsOK(chain::Vector{Dict{String, Any}}, chainName::String) Returns true if the chain of curves is contiguous and closed; false otherwise. """ From 2db2d2e183c27f005514883c72821375bed17620 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 16 Jun 2022 07:51:30 +0200 Subject: [PATCH 159/164] no longer export examples_dir to avoid warning / confusion --- examples/interactive_from_control_file.jl | 2 +- src/HOHQMesh.jl | 66 +++++++++++------------ test/runtests.jl | 10 ++-- test/test_examples.jl | 10 ++-- test/test_hqmtool_project.jl | 4 +- test/test_project_with_viz.jl | 2 +- 6 files changed, 45 insertions(+), 49 deletions(-) diff --git a/examples/interactive_from_control_file.jl b/examples/interactive_from_control_file.jl index 1e137f71..768232fc 100644 --- a/examples/interactive_from_control_file.jl +++ b/examples/interactive_from_control_file.jl @@ -11,7 +11,7 @@ using HOHQMesh # Set the file path of the control file to be read in for this example -all_features_control_file = joinpath( examples_dir() , "AllFeatures.control" ) +all_features_control_file = joinpath( HOHQMesh.examples_dir() , "AllFeatures.control" ) # Read in the HOHQMesh control file and create the project dictionary that stores # the different components of a mesh, i.e., boundary curves, refinement regions, etc. diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 7b649ec6..47622882 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -19,12 +19,40 @@ function __init__() end end +# +# Include functionality for HQMTool interactive reading and writing a model for HOHQMesh +# Note, The visualzation routines are included above in the `__init__` because +# Makie is required +# + +# Core interactive tool routines for control file readin, curve evaluation, etc. +include("ControlFile/ControlFileOperations.jl") +include("Curves/CurveOperations.jl") +include("Curves/Spline.jl") +include("Misc/DictionaryOperations.jl") +include("Misc/NotificationCenter.jl") +include("Model/Geometry.jl") + +# Project itself and some helper generic and undo functionality +include("Project/Project.jl") +include("Project/Generics.jl") +include("Project/Undo.jl") + +# Front facing API of the interactive tool for the `Project` +include("Project/BackgroundGridAPI.jl") +include("Project/ControlInputAPI.jl") +include("Project/CurvesAPI.jl") +include("Project/ModelAPI.jl") +include("Project/RefinementRegionsAPI.jl") +include("Project/RunParametersAPI.jl") +include("Project/SmootherAPI.jl") + +# Main routine that uses HOHQMesh to generate a mesh from an interactive `Project` +include("Mesh/Meshing.jl") + # Main wrapper to generate a mesh from a control file export generate_mesh -# Make the examples directory available to the user -export examples_dir - # Generic functions for the HQMTool interface export new, add!, @@ -302,36 +330,4 @@ Return the path to the directory with some example mesh setups. """ examples_dir() = joinpath(pathof(HOHQMesh) |> dirname |> dirname, "examples") - -# -# Include functionality for interactive reading and writing a model for HOHQMesh -# Note, The visualzation routines are included above in the `__init__` because -# Makie is required -# - -# Core interactive tool routines for control file readin, curve evaluation, etc. -include("ControlFile/ControlFileOperations.jl") -include("Curves/CurveOperations.jl") -include("Curves/Spline.jl") -include("Misc/DictionaryOperations.jl") -include("Misc/NotificationCenter.jl") -include("Model/Geometry.jl") - -# Project itself and some helper generic and undo functionality -include("Project/Project.jl") -include("Project/Generics.jl") -include("Project/Undo.jl") - -# Front facing API of the interactive tool for the `Project` -include("Project/BackgroundGridAPI.jl") -include("Project/ControlInputAPI.jl") -include("Project/CurvesAPI.jl") -include("Project/ModelAPI.jl") -include("Project/RefinementRegionsAPI.jl") -include("Project/RunParametersAPI.jl") -include("Project/SmootherAPI.jl") - -# Main routine that uses HOHQMesh to generate a mesh from an interactive `Project` -include("Mesh/Meshing.jl") - end # module diff --git a/test/runtests.jl b/test/runtests.jl index cb99f3a9..424db505 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,21 +9,21 @@ isdir(outdir) && rm(outdir, recursive=true) @testset "HOHQMesh.jl" begin @testset "examples_dir()" begin - @test occursin("examples", examples_dir()) + @test occursin("examples", HOHQMesh.examples_dir()) end @testset "generate_mesh()" begin - control_file = joinpath(examples_dir(), "GingerbreadMan.control") + control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") @test generate_mesh(control_file) isa String end @testset "generate_mesh(; verbose=true)" begin - control_file = joinpath(examples_dir(), "GingerbreadMan.control") + control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") @test generate_mesh(control_file, verbose=true) isa String end @testset "generate_mesh() in 2D with ABAQUS output" begin - control_file = joinpath(examples_dir(), "IceCreamCone_Abaqus.control") + control_file = joinpath(HOHQMesh.examples_dir(), "IceCreamCone_Abaqus.control") generate_mesh(control_file) parse_mesh = abaqus_read_mesh(joinpath(outdir, "IceCreamCone_Abaqus.inp")) # set some reference values for comparison. These are the corner IDs for element 114 @@ -32,7 +32,7 @@ isdir(outdir) && rm(outdir, recursive=true) end @testset "generate_mesh() in 3D with ABAQUS output" begin - control_file = joinpath(examples_dir(), "HalfCircle3DRot.control") + control_file = joinpath(HOHQMesh.examples_dir(), "HalfCircle3DRot.control") generate_mesh(control_file) parse_mesh = abaqus_read_mesh(joinpath(outdir, "HalfCircle3DRot.inp")) # set some reference values for comparison. These are the corner IDs for element 246 diff --git a/test/test_examples.jl b/test/test_examples.jl index e6d11030..901e8181 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -9,27 +9,27 @@ using Test @testset "Interactive Examples Tests" begin - test_file = joinpath(examples_dir(), "interactive_from_control_file.jl") + test_file = joinpath(HOHQMesh.examples_dir(), "interactive_from_control_file.jl") include(test_file) @test p.name == "AllFeatures" - test_file = joinpath(examples_dir(), "interactive_outer_boundary.jl") + test_file = joinpath(HOHQMesh.examples_dir(), "interactive_outer_boundary.jl") include(test_file) @test p.name == "IceCreamCone" - test_file = joinpath(examples_dir(), "interactive_outer_boundary_generic.jl") + test_file = joinpath(HOHQMesh.examples_dir(), "interactive_outer_boundary_generic.jl") include(test_file) N = getPolynomialOrder(p) # Test against the default polynomial order of 5 that gets reset in this include @test N == 5 - test_file = joinpath(examples_dir(), "interactive_outer_box_two_circles.jl") + test_file = joinpath(HOHQMesh.examples_dir(), "interactive_outer_box_two_circles.jl") include(test_file) format = getMeshFileFormat(p) # Test against the mesh file format type for this example @test format == "ABAQUS" - test_file = joinpath(examples_dir(), "interactive_spline_curves.jl") + test_file = joinpath(HOHQMesh.examples_dir(), "interactive_spline_curves.jl") include(test_file) spline = getCurve(p, "big_spline", "inner1") # Test against the number of spline knots from the testing file diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 3bc0bdde..aca6076f 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -48,7 +48,7 @@ using Test @test haskey(cDict,"SPRING_SMOOTHER") == false # read in the AllFeatures example - control_file = joinpath(examples_dir(), "AllFeatures.control") + control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p = openProject(control_file, projectPath) @test hasBackgroundGrid(p) == true @@ -73,7 +73,7 @@ using Test HOHQMesh.stringForKeyFromDictionary("CONTROL_INPUT", p.projectDictionary) # Use the NACA0012 example because it sets the background grid differently - control_file = joinpath(examples_dir(), "NACA0012.control") + control_file = joinpath(HOHQMesh.examples_dir(), "NACA0012.control") p = openProject(control_file, projectPath) sizes = [2.0, 2.0, 1.0] diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 48b357ad..8f446fcb 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -66,7 +66,7 @@ using CairoMakie projectPath = "out" - control_file = joinpath(examples_dir(), "AllFeatures.control") + control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p_file = openProject(control_file, projectPath) @test_nowarn plotProject!(p_file, MODEL+GRID) From 111cb8a0bfe78a1f1fe211bc9faa37633a15918e Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 23 Jun 2022 12:02:24 +0200 Subject: [PATCH 160/164] Update documentation with HQMTool (#17) * add authors section to docs * add contributing section to docs * add development section to the docs * typo fixes * update main docs page. missing links * ignore auto-generated authors file * separate HQMTool docs for better clarity. Add to CheatSheet.md * fix typo in filename * change header names in HQMTool docs * seperate workflow and HQMTool tour in docs * fix docstrings in background grid API * typo fix in workflow * section out the tour * point to the tour and tutorials * remove broken reference links * change name of section * update description in the tour * add information about HQMTool to the front page of docs * fix broken image link * small readibility edits * clarify the API * rearrange API docs section * point to Trixi docs for mesh format explanation * update comments in the tour * add link to tutorials introduction * fix typo in spline information * add tutorials section * add curved blob boundary tutorial * typo fixes in new docs files * typo fixes in interactive example scripts * add straight-sided two circles tutorial * add spline curves tutorial * clarify output of new splines tutorial * add description of the undo redo tutorial * update tutorial link in API docs * comment out unfinished doc file * docs should build now * typos fixes * state explicitly Julia compatibility * more typo fixes * first draft of editing curves tutorial * typos fixes and add synopsis of each tutorial to the main page * typo fixes in edit curve tutorial * typo fixes * add synopsis also to the top of tutorials * update section name of tutorials introduction * quality of life improvement where adding curves display a one line message * adjust wording to not call the project variable a dictionary * clean up exporting to only be front facing functions. Tests still pass * adjust tests with new exporting strategy * adjust comments in Undo and Meshing * change tutorial file name * edit docs for clarity * adjust file names in the docs --- .gitignore | 2 + AUTHORS.md | 24 + docs/make.jl | 31 +- docs/src/CheatSheet.md | 21 +- docs/src/HQMTool.md | 658 ------------------ docs/src/contributing.md | 54 ++ docs/src/development.md | 67 ++ docs/src/github-git.md | 227 ++++++ docs/src/guided-tour.md | 142 ++++ docs/src/index.md | 61 +- docs/src/interactive-api.md | 482 +++++++++++++ docs/src/interactive_overview.md | 152 ++++ docs/src/testing.md | 85 +++ docs/src/tutorials/create_edit_curves.md | 527 ++++++++++++++ docs/src/tutorials/curved_outer_boundary.md | 240 +++++++ docs/src/tutorials/introduction.md | 80 +++ docs/src/tutorials/spline_curves.md | 254 +++++++ docs/src/tutorials/straight_outer_boundary.md | 206 ++++++ examples/interactive_from_control_file.jl | 2 +- examples/interactive_outer_boundary.jl | 2 +- .../interactive_outer_boundary_generic.jl | 2 +- examples/interactive_outer_box_two_circles.jl | 7 +- examples/interactive_spline_curves.jl | 13 +- examples/test_spline_curve_data.txt | 78 +++ src/HOHQMesh.jl | 166 ++--- src/Mesh/Meshing.jl | 3 +- src/Project/BackgroundGridAPI.jl | 6 +- src/Project/ModelAPI.jl | 2 + src/Project/Project.jl | 2 +- src/Project/Undo.jl | 3 +- test/runtests.jl | 8 +- test/test_background_grid.jl | 18 +- test/test_curve.jl | 16 +- test/test_examples.jl | 2 +- test/test_hqmtool_project.jl | 8 +- test/test_project_with_viz.jl | 4 +- test/test_visualization.jl | 2 +- 37 files changed, 2808 insertions(+), 849 deletions(-) create mode 100644 AUTHORS.md delete mode 100644 docs/src/HQMTool.md create mode 100644 docs/src/contributing.md create mode 100644 docs/src/development.md create mode 100644 docs/src/github-git.md create mode 100644 docs/src/guided-tour.md create mode 100644 docs/src/interactive-api.md create mode 100644 docs/src/interactive_overview.md create mode 100644 docs/src/testing.md create mode 100644 docs/src/tutorials/create_edit_curves.md create mode 100644 docs/src/tutorials/curved_outer_boundary.md create mode 100644 docs/src/tutorials/introduction.md create mode 100644 docs/src/tutorials/spline_curves.md create mode 100644 docs/src/tutorials/straight_outer_boundary.md create mode 100644 examples/test_spline_curve_data.txt diff --git a/.gitignore b/.gitignore index d1dad9a6..ad972b16 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ **/Manifest.toml out*/ docs/build +docs/src/authors.md public/ coverage/ coverage_report/ @@ -8,3 +9,4 @@ coverage_report/ .vscode/ examples/*.tec examples/*.mesh +*.png diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 00000000..5ed020ed --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,24 @@ +# Authors + +HOHQMesh.jl is maintained by the +[Trixi authors](https://github.com/trixi-framework/Trixi.jl/blob/main/AUTHORS.md). +Its development is coordinated by the *principal developers* who are its main +contributors and can be contacted in case of questions about HOHQMesh. In addition, +there are *contributors* who have provided substantial additions or modifications. +The [*HOHQMesh*](https://github.com/trixi-framework/HOHQMesh) mesh generator itself +is developed by David A. Kopriva. + +## Principal Developers +* [David A. Kopriva](https://www.math.fsu.edu/~kopriva/), + Florida State University, USA +* [Andrew Winters](https://liu.se/en/employee/andwi94), + Linköping University, Sweden + +## Contributors +The following people contributed major additions or modifications to HOHQMesh and +are listed in alphabetical order: + +* David Kopriva +* Hendrik Ranocha +* Michael Schlottke-Lakemper +* Andrew Winters diff --git a/docs/make.jl b/docs/make.jl index 9381f223..facf11a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,6 +5,13 @@ using HOHQMesh # Define module-wide setups such that the respective modules are available in doctests DocMeta.setdocmeta!(HOHQMesh, :DocTestSetup, :(using HOHQMesh); recursive=true) +# Get Trixi root directory +hohqmesh_root_dir = dirname(@__DIR__) + +# Copy list of authors to not need to synchronize it manually +authors_text = read(joinpath(hohqmesh_root_dir, "AUTHORS.md"), String) +write(joinpath(@__DIR__, "src", "authors.md"), authors_text) + # Make documentation makedocs( # Specify modules for which docstrings should be shown @@ -15,17 +22,33 @@ makedocs( format = Documenter.HTML( # Disable pretty URLs during manual testing prettyurls = get(ENV, "CI", nothing) == "true", - # Explicitly add favicon as asset - # assets = ["assets/favicon.ico"], # Set canonical URL to GitHub pages URL canonical = "https://trixi-framework.github.io/HOHQMesh.jl/stable" ), # Explicitly specify documentation structure pages = [ "Home" => "index.md", - "Interactive mesh generation" => "HQMTool.md", - "Cheat sheet" => "CheatSheet.md", + "Interactive mesh generation" => [ + "interactive_overview.md", + "guided-tour.md", + "interactive-api.md", + "CheatSheet.md", + ], + "Tutorials" => [ + "Overview" => joinpath("tutorials", "introduction.md"), + joinpath("tutorials", "straight_outer_boundary.md"), + joinpath("tutorials", "curved_outer_boundary.md"), + joinpath("tutorials", "spline_curves.md"), + joinpath("tutorials", "create_edit_curves.md"), + ], + "Advanced topics & developers" => [ + "Development" => "development.md", + "GitHub & Git" => "github-git.md", + "Testing" => "testing.md", + ], "Reference" => "reference.md", + "Authors" => "authors.md", + "Contributing" => "contributing.md", "License" => "license.md" ], strict = true # to make the GitHub action fail when doctests fail, see https://github.com/neuropsychology/Psycho.jl/issues/34 diff --git a/docs/src/CheatSheet.md b/docs/src/CheatSheet.md index a7c6d200..89767bc9 100644 --- a/docs/src/CheatSheet.md +++ b/docs/src/CheatSheet.md @@ -1,11 +1,22 @@ -# HQMTool CheatSheet +# Commands Cheat Sheet -Workflow: +This provides a quick reference for the syntax +of the interactive construction of boundary curves, background grid, etc. +When possible, the commands presented below give +generic versions of the function calls, e.g., for creating a new curve or +adding the curve to a boundary chain. The script +`interactive_outer_boundary_generic.jl` in the `examples` folder +constructs an identical example mesh as shown in the [Guided tour](@ref) +using generic function calls. + +A thorough description of the functions can be found in the [API](@ref) section. + +The general workflow of the interactive mesh functionality within a REPL session is 1. Create a project 2. Add boundary curves -4. Add a background grid -3. Add manual refinement (if desired) +3. Add a background grid +4. Add manual refinement (if desired) 5. Generate mesh ## Project @@ -21,7 +32,7 @@ Workflow: updatePlot!(p, options) ``` -`options` are the sum of `GRID`, `MESH`, `MODEL`, `REFINEMENTS` +The `options` are any sum of `MODEL`, `GRID`, `REFINEMENTS`, and `MESH`. ## Curves ``` diff --git a/docs/src/HQMTool.md b/docs/src/HQMTool.md deleted file mode 100644 index 062a92cb..00000000 --- a/docs/src/HQMTool.md +++ /dev/null @@ -1,658 +0,0 @@ -# HQMTool -HQMTool is an API to generate a quad (Future:Hex) mesh using Julia. It serves as a front end to the HOHQMesh program, and is designed to let one build a meshing project interactively while graphically displaying the results. - -## Contents - -1. [Introduction](@ref) -2. [Basic Moves](@ref) -3. [HQMTool API](@ref) -1. [Project Creation and Saving](@ref) -2. [Plotting](@ref) -3. [Modifying/Editing a Project](@ref) -4. [Controlling the Mesh Generation Process](@ref) - 1. [Editing the Run Parameters](@ref) - 2. [Changing the output file names](@ref) - 3. [Adding the background grid](@ref) - 4. [Smoothing Operations](@ref) - 5. [Manual Refinement](@ref) -5. [Boundary Curves](@ref) - 1. [Adding and Removing Outer and Inner Boundaries](@ref) - 2. [Defining Curves](@ref) - 3. [Editing Curves](@ref) -6. [Undo/Redo](@ref) -4. [Advanced](@ref) - -## Introduction - -HQMTool is an API to build quad/hex meshes. Several examples are available in the `examples` folder -to get you started. These example scripts follow the naming convention of `interactive_*` where -the phrase interactive indicates their association with HQMTool and then trailing information -will indicate what that interactive demonstrates. For instance, the file `interactive_splines.jl` -provides an interactive project that creates an manipulates splines for the inner boundaries before -generating the mesh. - -Below we highlight three fundamental scripts that demonstrate the functionality of HQMTool. More in depth -explanations of the functionality is provided in the tutuorials TODO: ADD LINK - -First is a basic example script that reads in an existing control file from the HOHQMesh examples collection. -To run that example, execute -```julia - include("interactive_from_control_file.jl") -``` -This command will create mesh and plot files in the `out` directory. - -The second example `interactive_outer_boundary.jl` builds a new project consisting of an outer, -circular boundary, and an inner boundary in the shape of an ice cream cone. -The "verbose" example script, where all functions arevalled with their full name, is given below. -```julia -using HOHQMesh - -# Create a new project with the name "IceCreamCone", which will also be the -# name of the mesh, plot and stats files, written to output folder `out`. - -p = newProject("IceCreamCone", "out") - -# Outer boundary for this example mesh is a complete circle. Add it into the project. - -circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") -addCurveToOuterBoundary!(p, circ) - -# Inner boundary is three curves. Two straight lines and a circular arc. -# Note the three curve are connected to ensure a counter-clockwise orientation -# as required by HOHQMesh - -cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) -iceCream = newCircularArcCurve("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") -cone2 = newEndPointsLineCurve("cone2", [-1.0, 0.0, 0.0], [0.0, -3.0, 0.0]) -addCurveToInnerBoundary!(p, cone1, "IceCreamCone") -addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") -addCurveToInnerBoundary!(p, cone2, "IceCreamCone") - -# Adjust some `RunParameters` and overwrite the defaults values. In this case, we -# set a new value for the boundary order polynomial representation and adjust the -# output mesh file format to be `sem` - -setPolynomialOrder!(p, 4) -setPlotFileFormat!(p, "sem") - -# A background grid is required for the mesh generation. In this example we lay a -# background grid of Cartesian boxes with size 0.5. - -addBackgroundGrid!(p, [0.5, 0.5, 0.0]) - -# To plot the project model curves and the background grid, type `using GLMakie` -# in the REPL session, uncomment this line, and rerun this script - -# plotProject!(p, MODEL+GRID) - -# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` -# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is -# updated with the mesh that was generated. - -generate_mesh(p) - -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, -# the number of elements etc., are printed to the REPL -``` -The first line creates a new project, where the mesh and plot file names will be derived -from the project name, "IceCreamCone" written to the specified folder. - -To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, -if desired. As in HOHQMesh, there are four curve classes currently available: - -- Parametric equations -- Cubic Splines -- Lines defined by their end points -- Circular arcs - -In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] -with radius 4, starting at zero and ending at 360 degrees. It is added to the project with -`addCurveToOuterBoundary!`. You can add any number of curves to the outer boundary. - -Similarly, you create curves and add them to as many inner boundaries that you want to have. -In the example, there is one inner boundary, "IceCreamCone" made up of two straight lines and a half -circular arc. Again, they are defined counter-clockwise. - -For convenience, `newProject` will generate default run parameters used by HOHQMesh, like the plot file format -and the smoother. The parameters can be edited with setter commands. For example, the script -sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). - -One run parameter that must be set manually is the background grid. Since there is an outer -boundary, that determines the extent of the domain to be meshed, so only the mesh size needs -to be specified using -``` - addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) -``` - -The example sets the background mesh size to be 0.1 in the x and y directions. -The z component is ignored. - -The script finishes by generating the quad mesh and plotting the results, as shown below - -![iceCreamCone](https://user-images.githubusercontent.com/25242486/162193980-b80fb92c-2851-4809-af01-be856152514f.png) - -Finally, the script returns the project so that it can be edited further, if desired. - -To save a control file for HOHQMesh, simply invoke -``` - saveProject(proj::Project, outFile::String) -``` -where outFile is the name of the control file (traditionally with a .control extension). -`saveProject` is automatically called when a mesh is generated. - -The third example `ice_cream_cone_demo` is identical to that which was explained above -except that the function calls use the generic versions of functions, e.g., `new` or `add!`. - -Methods are available to edit a model. For example to move the center of the outer boundary. - -## Basic Moves - -To generate a mesh using HQMTool you - -1. [Create a project](#newProject) - - ``` - p = newProject(,) - ``` - -2. [Create inner and outer boundary curves](#DefiningCurves) - - ``` - c = newEndPointsLineCurve(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* - c = newCircularArcCurve(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* - c = newParametricEquationCurve(, xEqn, yEqn, zEqn) *Parametric equation* - c = newSplineCurve(, dataFile) *Spline with data from a file* - c = newSpline(, nKnots, knotsMatrix) *Spline with given knot values* - ``` - -The generic name for each of these curve creation methods is `new!. The generic can be used instead of the longer descriptive name to save typing during interactive sessions, if desired. - - -3. [Add curves](#AddingCurves) to build the model to see what you have added, - - ``` - addOuterBoundaryCurve!(p, ) *Add outer boundary curve* - addInnerBoundaryCurve!(p, , ) *Add curve to an inner boundary* - ``` -Curves can be added by using the generic `add!` function instead of the longer descriptive name to save typing during interactive sessions, if desired. - -4. To [visualize](#Plotting) the project's model, - - ``` - plotProject!(p, MODEL) - ``` - - Plots are updated in response to user interactions. However, to update the plot at any time, use - - ``` - updatePlot!(p, options) - ``` - - Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. - `MODEL`+`GRID` or `MODEL`+`MESH`. (You normally are not interested in the background grid once - the mesh is generated.) - -5. Set the [background grid](#(#BackgroundGrid)) - - When no outer boundary curve is present, the background grid can be set with - - ``` - addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) - ``` - - Or - - ``` - addBackgroundGrid!(p, [top value, left value, bottom value, right value], num Intervals [nX,nY,nZ]) - ``` - - The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by - `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent - [top value, left value, bottom value, right value] and the number of elements in each direction. The first exists for historical reasons; the second is probably the easiest to use. - - When an outer boundary is present the background grid can be set as - - ``` - addBackgroundGrid!(p,[dx,dy,dz]) - ``` - - where the spacing controls the number of elements in each direction. - -6. [Adjust parameters](#RunParameters), if desired - - ``` - setPolynomialOrder!(p,order) - ``` - -7. Generate the mesh - - ``` - generate_mesh(p) - ``` - - The mesh will be stored in `` with the name `.mesh`. The control file will also be - saved in that folder with the name `.control`, which you can read in again later and modify, - remesh, etc. The function will print the mesh information and statistics, and will plot the mesh as in - the figure above, if a plot is otherwise visible. If not, it can always be plotted with the `plotProject!` - command. - - -The ordering of the basic moves follows a logical pattern: The project must be created first. Curves can be added at any time. The background grid can be added any time to the project. A mesh is ususally generated after the model (curves) and background grid are completed. - -## HQMTool API - -### Project Creation and Saving - -#### New Project -``` - [Return:Project] proj = newProject(name::String, folder::String) -``` -The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is -the directory in which those files will be placed. The empty project will include default `RunParameters` -and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to -add is the [background grid](#BackgroundGrid). - -#### Opening an existing project file - -A project can be created from an existing HOHQMesh control file with -``` - [Return:Project] proj = openProject(fileName::String, folder::String) -``` -The supplied `fileName` will be the name of the project and the generated mesh and plot files will be placed -in the supplied `folder`. - -#### Saving a project -``` - saveProject(proj::Project) -``` -writes a control file to the folder designated when creating the new project. -It can be read in again with `openProject`. - -### Plotting - -#### Plotting a Project -``` - plotProject!(proj::Project, options) -``` -The options are any combination of `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. `GRID` refers to the background grid, -which you an view to make sure that it can resolve the boundary curves in the model. -Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. `REFINEMENTS` will show -where [manual refinement](#ManualRefinement) is placed. - -If the model is modified and you want to re-plot with the new values, invoke -``` - updatePlot!(proj::Project, options) -``` -but generally the plot will be updated automatically as you build the model. - -### Modifying/Editing a Project - -#### Setting the name of a project - -The project name is the name under which the mesh, plot, statistics and control files will be written. -``` - setName!(proj::Project,name::String) -``` - -#### Getting the current name of a Project -``` - [Return:String] getName(proj::Project) -``` - -### Controlling the Mesh Generation Process - -#### Editing the Run Parameters - -The run parameters can be enquired and set with these getter/setter pairs: -``` - [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) - [Return:Int] getPolynomialOrder(proj::Project) - [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) - [Return:String] getMeshFileFormat(proj::Project) - [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) - [Return:String] getPlotFileFormat(proj::Project) -``` - -The available mesh file formats are `"ISM"`, `"ISM-V2"`, or `"ABAQUS"`. The plot file (which can be viewed with something -like VisIt or Paraview) format is either `"skeleton"` or `"sem"`. The former is just a low order finite element -represntation of the mesh. The latter (which is a much bigger file) includes the interior degrees of freedom. - -#### Changing the output file names - -By default, the mesh, plot and stats files will be written with the name and path supplied when -newProject is called. They can be changed/enquired with -``` - [Return:nothing] setName!(proj::Project,name::String) - [Return:String] getName(proj::Project) - [Return:nothing] setFolder!(proj::Project,folder::String) - [Return:String] getFolder(proj::Project) -``` - -#### Adding the background grid - -There are three forms for the background grid definition, one for when there is an outer boundary, -and two for when there is not. One or the other has to be specified after a new project has been created. -``` - [Return:nothing] addBackgroundGrid!(proj::Project, x0::Array{Float64}, dx::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, box::Array{Float64}, N::Array{Int}) - [Return:nothing] addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) -``` -Use one of the first two if there is no outer boundary present in the model. With the first, a rectangular -outer boundary will be created of extent `[x0[1], x0[1] + N*dx[1]]` by `[x0[2], x0[2] + N*dx[2]]`. -The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. -The arrays `x0`, `dx`, `N`, `bgSize` are all vectors `[ *, *, * ]` giving the x, y, and z components. - -#### Smoothing Operations - -A default smoother is created when `newProject` is called, which sets the status to `ON`, type to -`LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. -The most likely parameter to change is the number of iterations. - -To change the defaults, the smoother parameters can be set/enquired with the functions -``` - [Return:nothing] setSmoothingStatus!(proj::Project, status::String) - [Return:String] getSmoothingStatus(proj::Project) - [Return:nothing] setSmoothingType!(proj::Project, type::String) - [Return:String] getSmoothingType(proj::Project) - [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) - [Return:Int] getSmoothingIterations(proj::Project) -``` -The smooth `status` is either "ON" or "OFF". - -To remove the smoother altogether, -``` - [Return:nothing] removeSpringSmoother!(proj::Project) -``` - -#### Manual Refinement - -Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, -using a `RefinementLine`. You can have as many of these as you want. They are useful if you know regions of -the solution where refinement is needed (e.g. a wake) or in problematic areas in the geometry. - -To create a refinement center, -``` - [Return:Dict{String,Any}] newRefinementCenter!(proj::Project, - type::String, - x0::Array{Float64}, - h::Float64, - w::Float64) -``` -where the type is either "smooth" or "sharp", `x0` = [x, y, z] is the location of the center, `h` is the mesh size, -and `w` is the extent of the refinement region. The z component must be zero. - -Similarly, one can create a `RefinementLine`, -``` - [Return:Dict{String,Any}] newRefinementLine!(proj::Project, type::String, - x0::Array{Float64}, x1::Array{Float64}, - h::Float64, - w::Float64) -``` -where `x0` is the start postition and `x1` is the end of the line. - -To add a refinement region to the project, -``` - [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) -``` - -To get a reference to a refinement region with a given name, use -``` - [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) -``` - -Finally, to get a list of all the refinement regions, -``` - [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) -``` - -A refinement region can be edited by using the following: -``` - [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) - [Return:String] getRefinementType(r::Dict{String,Any}) - [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) - [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) - [Return:Float64] getRefinementGridSize(r::Dict{String,Any}) - [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) - [Return:Float64] getRefinementWidth(r::Dict{String,Any}) -``` -where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. - -To further edit a `RefinementLine`, use the methods -``` - [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) - [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) - [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) -``` - -### Boundary Curves - -#### Adding and Removing Outer and Inner Boundaries - -1. Adding an outer boundary curve - - Using the curve creation routines, described in the next section below, create curves counter-clockwise along the outer boundary and add them to the outer boundary curve using - - ``` - [Return:nothing] addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) - Generic: add!(...) - ``` - - `crv` is the dictionary that represents the curve. - - Example: - - ```julia - circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") - add!(p, circ) - ``` - -2. Adding an inner boundary curve - - The syntax is analogous to the creation of an outer boundary curve where. - - ``` - [Return:nothing] addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundaryName::String) - Generic: add!(...) - ``` - - Example: - - ```julia - cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) - add!(p, cone1, "IceCreamCone") - ``` - - To edit curves they can be accessed by name: - - ``` - [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, curveName::String, boundaryName::String) - Generic: getCurve(...) - [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, name::String) - Generic: getCurve(...) - ``` - -3. Deleting boundary curves - - The entire outer boundary or an entire inner boundary can be removed from the project. - - ``` - [Return:nothing] removeOuterBoundary!(proj::Project) - [Return:nothing] removeInnerBoundary!(proj::Project, boundaryName::String) - ``` - - Alternatively, individual pieces of the boundary curve chains can be removed. - - ``` - [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) - Generic: remove!(...) - [Return:nothing] removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) - Generic: remove!(...) - ``` - - As in HOHQMesh the project can have only one outer boundary chain, so the removal does not - require a specific `chainName`. - -#### Defining Curves - -Four curve types can be added to the outer and inner boundary curve chains. They are - -- Parametric equations -- Cubic Splines -- Lines defined by their end points -- Circular arcs - -##### Parametric Equations - -Creating a new curve equation -``` - [Return:Dict{String,Any}] newParametricEquationCurve(name::String, - xEqn::String, - yEqn::String, - zEqn::String = "z(t) = 0.0") - Generic: new(...) -``` -Returns a new set of parametric equation. Equations must be of the form -``` - () = ... -``` -The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. -The constant `pi` is defined for use. Exponention is done with `^`. All number literals are interpreted -as floating point numbers. - -Example: -``` - x(s) = 2.0 + 3*cos(2*pi*s)^2 -``` -The z-Equation is optional, but for now must define zero for z by default. - -##### Cubic Spline Curve - -A cubic spline is defined by an array of knots, tj,xj,yj,zj. -It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define -the t,x,y,z values, e.g. -``` - 9 - 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 - 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 - 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 - 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 - 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 - 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 - 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 - 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 - 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 -``` -or by constructing the `nKnots` x `4` array and supplying it to the new procedure. The respective constructors are -``` - [Return:Dict{String,Any}] newSplineCurve(name::String, dataFile::String) - Generic: new(...) - [Return:Dict{String,Any}] newSplineCurve(name::String, nKnots::Int, data::Matrix{Float64}) - Generic: new(...) -``` -If the spline curve is to be closed. The last data point must be the same as the first. - -##### Line Defined by End Points - -A straight line is constructed with -``` - [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, - xStart::Array{Float64}, - xEnd::Array{Float64}) - Generic: new(...) -``` -The `xStart` and `xEnd` are arrays of the form [x, y, z]. The `z` component should be zero and for now is ignored. - -Example: -``` - cone1 = new("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) -``` - -##### Circular Arc -``` - [Return:Dict{String,Any}] newCircularArcCurve(name::String, - center::Array{Float64}, - radius::Float64, - startAngle::Float64, - endAngle::Float64, - units::String) - Generic: new(...) -``` -The center is an array of the form [x, y, z]. The units argument defines the start and end angle units. -It is either "degrees" or "radians". That argument is optional, and defaults to "degrees". - -Example: -``` - iceCream = new("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") -``` - -#### Editing Curves - -You can determine the type of a curve by -``` - [Return:String] getCurveType(crv::Dict{String,Any}) -``` - -For any of the curves, their name can be changed by -``` - setCurveName!(crv::Dict{String,Any}, name::String) -``` -and checked by -``` - getCurveName(crv::Dict{String,Any}) -``` - -Otherwise there are special functions to change the parameters of curves -``` - [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) - [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) - [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) - [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) - [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) - - [Return:String] getXEqn(crv::Dict{String,Any}) - [Return:String] getYEqn(crv::Dict{String,Any}) - [Return:String] getZEqn(crv::Dict{String,Any}) - [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) - [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) - [Return:String] getArcUnits(arc::Dict{String,Any}) - [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) - [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) - [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) - [Return:Float64] getArcRadius(arc::Dict{String,Any}) -``` - -### Undo/Redo - -The HQMTool has unlimited undo/redo for most actions. - -In interactive mode, actions can be undone by the commands -``` - [Return:String] undo() - [Return:String] redo() -``` -where the return string contains the name of the action performed. - -To find out what the next actions are, use -``` - [Return:String] undoActionName() - [Return:String] redoActionName() -``` - -Finally, to clear the undo stack, use -``` - [Return:nothing] clearUndoRedo() -``` - -## Advanced - -All curves are actually dictionaries of type `Dict{String, Any}`, and since Julia is not a particularly object oriented language, -the parameters can be accessed and edited directly by key and value. In fact, all objects except for the Project, -are of type `Dict{String, Any}`. The project holds all the control and model objects in its `projectDirectory`. -However, if you do that, then undo/redo and plot updating won't happen. \ No newline at end of file diff --git a/docs/src/contributing.md b/docs/src/contributing.md new file mode 100644 index 00000000..7f523353 --- /dev/null +++ b/docs/src/contributing.md @@ -0,0 +1,54 @@ +# Contributing + +HOHQMesh.jl is an open-source project and we are very happy to accept contributions +from the community. Please feel free to open issues or submit patches (preferably +as merge requests) any time. For planned larger contributions, it is often +beneficial to get in contact with one of the principal developers first (see +[Authors](@ref)). + +HOHQMesh.jl and its contributions are licensed under the MIT license (see +[License](@ref)). As a contributor, you certify that all your +contributions are in conformance with the *Developer Certificate of Origin +(Version 1.1)*, which is reproduced below. + +## Developer Certificate of Origin (Version 1.1) +The following text was taken from +[https://developercertificate.org](https://developercertificate.org): + + Developer Certificate of Origin + Version 1.1 + + Copyright (C) 2004, 2006 The Linux Foundation and its contributors. + 1 Letterman Drive + Suite D4700 + San Francisco, CA, 94129 + + Everyone is permitted to copy and distribute verbatim copies of this + license document, but changing it is not allowed. + + + Developer's Certificate of Origin 1.1 + + By making a contribution to this project, I certify that: + + (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + + (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + + (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + + (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. diff --git a/docs/src/development.md b/docs/src/development.md new file mode 100644 index 00000000..4ea9c970 --- /dev/null +++ b/docs/src/development.md @@ -0,0 +1,67 @@ +# Development + +## Text editors +When writing code, the choice of text editor can have a significant impact on +productivity and developer satisfaction. While using the default text editor +of the operating system has its own benefits (specifically the lack of an explicit +installation procure), usually it makes sense to switch to a more +programming-friendly tool. In the following, a few of the many options are +listed and discussed: + +### VS Code +[Visual Studio Code](https://code.visualstudio.com/) is a modern open source +editor with [good support for Julia](https://github.com/julia-vscode/julia-vscode). +While [Juno](#Juno) had some better support in the past, the developers of Juno +and the Julia VS Code plugin are joining forces and concentrating on VS Code +since support of Atom has been suspended. Basically, all comments on [Juno](#Juno) +below also apply to VS Code. + +### Juno +If you are new to programming or do not have a preference for a text editor +yet, [Juno](https://junolab.org) is a good choice for developing Julia code. +It is based on *Atom*, a sophisticated and widely used editor for software +developers, and is enhanced with several Julia-specific features. Furthermore +and especially helpful for novice programmers, it has a MATLAB-like +appearance with easy and interactive access to the current variables, the +help system, and a debugger. + +### Vim or Emacs +Vim and Emacs are both very popular editors that work great with Julia. One +of their advantages is that they are text editors without a GUI and as such +are available for almost any operating system. They also are preinstalled on +virtually all Unix-like systems. However, Vim and Emacs come with their own, +steep learning curve if they have never been used before. Therefore, if in doubt, it +is probably easier to get started with a classic GUI-based text editor (like +Juno). If you decide to use Vim or Emacs, make sure that you install the +corresponding Vim plugin +[julia-vim](https://github.com/JuliaEditorSupport/julia-vim) or Emacs major +mode [julia-emacs](https://github.com/JuliaEditorSupport/julia-emacs). + + + +## Releasing a new version of HOHQMesh + +- Check whether everything is okay, tests pass etc. +- Set the new version number in `Project.toml` according to the Julian version of semver. + Commit and push. +- Comment `@JuliaRegistrator register` on the commit setting the version number. +- `JuliaRegistrator` will create a PR with the new version in the General registry. + Wait for it to be merged. +- Increment the version number in `Project.toml` again with suffix `-pre`. For example, + if you have released version `v0.2.0`, use `v0.2.1-pre` as new version number. + + + +## Preview the documentation + +You can build the documentation of HOHQMesh.jl locally by running +```bash +julia --project=docs -e 'using Pkg; Pkg.instantiate(); include("docs/make.jl")' +``` +from the HOHQMesh.jl main directory. Then, you can look at the html files generated in +`docs/build`. +For PRs triggered from branches inside the HOHQMesh.jl main repository previews of +the new documentation are generated at `https://trixi-framework.github.io/HOHQMesh.jl/previews/PRXXX`, +where `XXX` is the number of the PR. +Note, this does not work for PRs from forks for security reasons (since anyone could otherwise push +arbitrary stuff, including malicious code). \ No newline at end of file diff --git a/docs/src/github-git.md b/docs/src/github-git.md new file mode 100644 index 00000000..bef9991c --- /dev/null +++ b/docs/src/github-git.md @@ -0,0 +1,227 @@ +# GitHub & Git + +This page contains information on how to use GitHub and Git when developing +HOHQMesh. + +## Development workflow + +For adding modifications to HOHQMesh, we generally follow these steps: + +### Create an issue (optional) +In many cases it makes sense to start by creating an issue on GitHub. For +example, if the implementation approach for a new feature is not yet clear or if +there should be a discussion about the desired outcome, it is good practice to +first get a consensus on what is the expected result of this modification. A +GitHub issue is *the* place to lead this discussion, as it preserves it in the +project and - together with the actual code changes - allows in the future to revisit +the reasons for a particular choice of implementation or feature. + +### Create a branch and *immediately* create a pull request +All feature development, bug fixes etc. should be developed in a branch and not +directly on `main`. If you do not have write access to the main repository on +GitHub, first create a fork of the HOHQMesh.jl repository and clone the fork to +your machine. Then, create a branch locally by executing `git checkout -b +yourbranch`, push it to the repository, and create a pull request (PR). + +If you have already cloned HOHQMesh.jl from the main repo to your local machine, +you can also work in that clone. You just need to add your fork as additional +remote repository and push your new branch there. +```bash +git remote add myfork git@github.com:YOUR_NAME/HOHQMesh.jl.git +# get latest main from the main repo +git checkout main +git pull +# create a new branch for a cool new feature, bug fix, ... +git checkout -b YOUR_BRANCH_NAME +# do some work and push it to your fork +git push -u myfork +# go to https://github.com/trixi-framework/HOHQMesh.jl/pull +# and create a PR from your new branch +``` + +!!! info "Why using pull requests?" + Immediately creating a PR for your branch has the benefit that all + code discussions can now be held directly next to the corresponding code. Also, + the PR allows to easily compare your branch to the upstream branch + (usually `main`) to see what you have changed. Moreover, tests will run + automatically. + +### Make changes +With a branch and PR in place, you can now write your code and commit +it to your branch. If you request feedback from someone else, make sure to push +your branch to the repository such that the others can easily review your +changes or dive in and change something themselves. + +!!! warning "Avoid committing unwanted files" + When you use `git add .` or similar catch-all versions, make sure you do not + accidentally commit unwanted files (e.g., HOHQMesh output plot and mesh files). + If it happens anyways, you can undo the last commit (also + multiple times) by running `git reset HEAD~` (see also [Undo last + commit](@ref)). However, this strategy only works if you have **not yet + pushed your changes**. If you *did* push your changes, please talk to one of + the principal developers on how to proceed. + +### Keep your branch in sync with `main` +For larger features with longer-living branches, it may make sense to +synchronize your branch with the current `main`, e.g., if there was a bug fix +in `main` that is relevant for you. In this case, perform the following steps to +merge the current `main` to your branch: + + 1. Commit all your local changes to your branch and push it. This allows you to + delete your clone in case you make a mistake and need to abort the merge. + 2. Execute `git fetch` to get the latest changes from the repository. + 3. Make sure you are in the correct branch by checking the output of `git status` + or by running `git checkout yourbranch`. + 4. Merge main using `git merge main`. If there were no conflicts, hooray!, + you are done. Otherwise you need to resolve your merge conflicts and commit + the changes afterwards. A good guide for resolving merge conflicts can be + found + [here](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-using-the-command-line). + +In general, always use `git merge` and not `git rebase` to get the latest +changes from `main`. It is less error-prone and does not create problems on +branches that are worked on collaboratively. + +### Prepare for review +If you feel like your branch is ready to be merged to `main`, prepare it for +review. That is, you should + + * merge the current `main` to your branch + * run tests if available, but at least ensure that you did not accidentally + change the results for one of the existing example elixirs + * properly comment your code + * delete old/unused code, especially commented lines (unless they contain + helpful code, in which case you should add a comment on why you keep this + around) + * remove debug statements + * add a script `interactive_xxx.jl` that uses your feature (only relevant for new + features within the interactive mesh funtionality) + * describe changes in `NEWS.md` if appropriate + +After you are confident that your branch is cleaned up properly, commit all +changes and push them to the repository. + +### Get reviewed +Ask one of the principal developers to review your code. This review will be +conducted asynchronously, with the reviewer leaving comments and annotations in the PR. +In some cases it will be necessary to do multiple rounds of reviews, especially if +there are larger changes to be added. Just commit and push your changes to your +branch, and the corresponding pull request will be updated automatically. + +Please note that a review has nothing to do with the lack of experience of the +person developing changes: We try to review all code before it gets added to +`main`, even from the most experienced developers. This is good practice and +helps to keep the error rate low while ensuring the the code is developed in a +consistent fashion. Furthermore, do not take criticism of your code personally - +we just try to keep HOHQMesh as accessible and easy to use for everyone. + +### Merge branch +Once your branch is reviewed and declared ready for merging by the reviewer, +make sure that all the latest changes have been pushed. Then, one of the +developers will merge your PR. If you are one of the developers, you can also go +to the pull request page on GitHub and and click on **Merge pull request**. +Voilá, you are done! Your branch will have been merged to +`main` and the source branch will have been deleted in the GitHub repository +(if you are not working in your own fork). + +### Update your working copy +Once you have merged your branch by accepting the PR on GitHub, you +should clean up your local working copy of the repository by performing the +following steps: + + 1. Update your clone by running `git fetch`. + 2. Check out `main` using `git checkout main`. + 3. Delete merged branch locally with `git branch -d yourbranch`. + 4. Remove local references to deleted remote branch by executing `git remote + prune origin`. + +You can now proceed with your next changes by starting again at the top. + + +## Using Git + +### Resources for learning Git +Here are a few resources for learning do use Git that at least one of us found +helpful in the past (roughly ordered from novice to advanced to expert): + + * [Git Handbook by GitHub](https://guides.github.com/introduction/git-handbook/) + * [Learn Git Branching](https://learngitbranching.js.org/) + +### Tips and tricks +This is an unordered collection of different tips and tricks that can be helpful +while working with Git. As usual, your mileage might vary. + +#### Undo last commit +If you made a mistake in your last commit, e.g., by committing an unwanted file, +you can undo the latest commit by running +```bash +git reset HEAD~ +``` +This only works if you have not yet pushed your branch to the GitHub repository. +In this case, please talk to one of the core developers on how to proceed. +Especially when you accidentally committed a large file (image, or video), please +let us know as fast as possible, since the effort to fix the repository grows +considerably over time. + +#### Remove large file from repository +If a large file was accidentally committed **and pushed** to the HOHQMesh +repository, please talk to one of the principal developers as soon as possible so +that they can fix it. + +!!! danger "Large files" + You should never try to fix this yourself, as it potentially + disrupts/destroys the work of others! + +Based on the instructions found +[here](https://rtyley.github.io/bfg-repo-cleaner/) and +[here](https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository), +the following steps need to be taken (as documented for GitLab in issue +[#33](https://github.com/trixi-framework/Trixi.jl/issues/33)): + + 1. Tell everyone to commit and push their changes to the repository. + 2. Fix the branch in which the file was committed by removing it and committing + the removal. This is especially important on `main`. + 3. Perform the following steps to clean up the Git repository: + ```bash + cd /tmp + + # Download bfg-1.13.0.jar from https://rtyley.github.io/bfg-repo-cleaner/ + + # Get fresh clone of repo (so you can throw it away in case there is a problem) + git clone --mirror git@github.com:trixi-framework/HOHQMesh.jl.git + + # Clean up repo of all files larger than 10M + java -jar bfg-1.13.0.jar --strip-blobs-bigger-than 10M HOHQMesh.jl.git + + # Enter repo + cd Trixi.jl.git + + # Clean up reflog and force aggressive garbage collection + git reflog expire --expire=now --all && git gc --prune=now --aggressive + + # Push changes + git push + + # Delete clone + rm -rf HOHQMesh.jl.git + ``` + 4. Tell everyone to clean up their local working copies by performing the + following steps (also do this yourself): + ```bash + # Enter repo + cd HOHQMesh.jl + + # Get current changes + git fetch + + # Check out the fixed branch + git checkout branchname + + # IMPORTANT: Do a rebase instead of a pull! + git rebase + + # Clean reflog and force garbage collection + git reflog expire --expire=now --all && git gc --prune=now --aggressive + ``` + **IMPORTANT**: You need to do a `git rebase` instead of a `git pull` when + updating the fixed branch. diff --git a/docs/src/guided-tour.md b/docs/src/guided-tour.md new file mode 100644 index 00000000..2dc7ceaa --- /dev/null +++ b/docs/src/guided-tour.md @@ -0,0 +1,142 @@ +# Guided tour + +In this brief overview, we highlight two scripts from the `examples` folder +that demonstrate the interactive mesh functionality of HOHQMesh.jl. In depth +explanations of the functionality are provided in the [Tutorials](@ref). + +See the [HOHQMesh documentation](https://trixi-framework.github.io/HOHQMesh/) +for more details about its terminology and capabilities. + +## Mesh from a control file + +A first example script reads in an existing control file from the HOHQMesh examples collection +and makes it into a `Project`. +To run this example, execute +```julia +julia> include(joinpath(HOHQMesh.examples_dir(), "interactive_from_control_file.jl")) +``` +This command will create mesh and plot files in the `out` directory. + +## Build a mesh from scratch + +A second example script `interactive_outer_boundary.jl` makes a new project consisting +of an outer, circular boundary, and an inner boundary in the shape of an ice cream cone. +To run this example, execute +```julia +julia> include(joinpath(HOHQMesh.examples_dir(), "interactive_outer_boundary.jl")) +``` + +For completeness, we provide the example script and walk-through each step in the construction +of the `Project` below. +```julia +using HOHQMesh + +# Create a new project with the name "IceCreamCone", which will also be the +# name of the mesh, plot and stats files, written to output folder `out`. + +p = newProject("IceCreamCone", "out") + +# Outer boundary for this example mesh is a complete circle. Add it into the project. + +circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") +addCurveToOuterBoundary!(p, circ) + +# Inner boundary is three curves. Two straight lines and a circular arc. +# Note the three curve are connected to ensure a counter-clockwise orientation +# as required by HOHQMesh + +# Create the three interior curves. The individual names of each curve in the inner +# chain are used internally by HOHQMesh and are output as the given boundary names in +# the mesh file. + +cone1 = newEndPointsLineCurve("cone1", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) +iceCream = newCircularArcCurve("iceCream", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") +cone2 = newEndPointsLineCurve("cone2", [-1.0, 0.0, 0.0], [0.0, -3.0, 0.0]) + +# Assemble the three curve in a closed chain oriented counter-clockwise. The chain +# name `IceCreamCone` is only used internally by HOHQMesh. + +addCurveToInnerBoundary!(p, cone1, "IceCreamCone") +addCurveToInnerBoundary!(p, iceCream, "IceCreamCone") +addCurveToInnerBoundary!(p, cone2, "IceCreamCone") + +# Adjust some `RunParameters` and overwrite the defaults values. In this case, we +# set a new value for the boundary order polynomial representation and adjust the +# output mesh file format to be `sem` + +setPolynomialOrder!(p, 4) +setPlotFileFormat!(p, "sem") + +# A background grid is required for the mesh generation. In this example we lay a +# background grid of Cartesian boxes with size 0.5. + +addBackgroundGrid!(p, [0.5, 0.5, 0.0]) + +# Plot the project model curves and background grid + +if isdefined(Main, :Makie) + plotProject!(p, MODEL+GRID) + @info "Press enter to generate the mesh and update the plot." + readline() + else # Throw an informational message about plotting to the user + @info "To visualize the project (boundary curves, background grid, mesh, etc.), include `GLMakie` and run again." + end + +# Generate the mesh. This produces the mesh and TecPlot files `AllFeatures.mesh` and `AllFeatures.tec` +# and save them to the `out` folder. Also, if there is an active plot in the project `p` it is +# updated with the mesh that was generated. + +generate_mesh(p) + +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, +# the number of elements etc., are printed to the REPL +``` +The first line creates a new project, where the mesh and plot file names will be derived +from the project name, "IceCreamCone" written to the specified folder. + +To develop the model, one adds curves to the outer boundary or to multiple inner boundaries, +if desired. As in HOHQMesh, there are four curve classes currently available: + +- Parametric equations +- Cubic Splines +- Lines defined by their end points +- Circular arcs + +In the example, the outer boundary is a closed circular arc with center at [0.0, 0.0, 0.0] +with radius 4, starting at zero and ending at 360 degrees. It is added to the project with +`addCurveToOuterBoundary!`. You can add any number of curves to the outer boundary. + +Similarly, you create curves and add them to as many inner boundaries that you want to have. +In the example, there is one inner boundary, "IceCreamCone" made up of two straight lines and a half +circular arc. Again, they are defined counter-clockwise. + +For convenience, `newProject` will generate default run parameters used by HOHQMesh, like the plot file format +and the smoother. The parameters can be edited with setter commands. For example, the script +sets the polynomial order (default = 5) and the plot file format (default = "skeleton"). + +One run parameter that must be set manually is the background grid. Since there is an outer +boundary, that determines the extent of the domain to be meshed, so only the mesh size needs +to be specified using +``` +addBackgroundGrid!(proj::Project, bgSize::Array{Float64}) +``` + +The example sets the background mesh size to be 0.1 in the x and y directions. +The z component is ignored. + +The script finishes by generating the quad mesh and plotting the results, as shown below + +![iceCreamCone](https://user-images.githubusercontent.com/25242486/162193980-b80fb92c-2851-4809-af01-be856152514f.png) + +Finally, the script returns the project so that it can be edited further, if desired. + +To save a control file for HOHQMesh, simply invoke +``` +saveProject(proj::Project, outFile::String) +``` +where `outFile` is the name of the control file (traditionally with a .control extension). +`saveProject` is automatically called when a mesh is generated. + +Note, a third example script `interactive_outer_boundary_generic.jl` is identical to that +which was explained above except that the function calls use the generic versions of +functions, e.g., `new` or `add!`. diff --git a/docs/src/index.md b/docs/src/index.md index c2db6000..32709ff9 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,15 +1,19 @@ # HOHQMesh.jl -This package is a thin Julia wrapper around the *High Order Hex-Quad Mesher* +This package is a Julia frontend to the Fortran-based *High Order Hex-Quad Mesher* (a.k.a. [**HOHQMesh**](https://github.com/trixi-framework/HOHQMesh)) created and developed by -[David A. Kopriva](https://www.math.fsu.edu/~kopriva/). +[David A. Kopriva](https://www.math.fsu.edu/~kopriva/). It augments HOHQMesh with +[interactive functionality](@ref InteractiveTool) that gives a user the ability to create, visualize, +and generate high-order meshes. +It further allows one to seamlessly integrate meshes generated by HOHQMesh into a Julia-based simulation workflow. +For example, running a simulation on an unstructured quadrilateral mesh +with [Trixi.jl](https://trixi-framework.github.io/Trixi.jl/stable/tutorials/hohqmesh_tutorial/). HOHQMesh.jl is available on Linux, MacOS, and Windows. - ## Installation If you have not yet installed Julia, please [follow the instructions for your operating system](https://julialang.org/downloads/platform/). HOHQMesh.jl works -with Julia v1.6. +with Julia v1.6 and above. HOHQMesh.jl is a registered Julia package. Hence, you can install it by executing the following commands in the Julia REPL: @@ -33,7 +37,7 @@ Two 2D examples `GingerbreadMan` and `NACA0012` and a 3D example `Snake` (all from HOHQMesh itself) come delivered with this package. You can generate a mesh for them by executing ```julia -julia> control_file = joinpath(examples_dir(), "GingerbreadMan.control") +julia> control_file = joinpath(HOHQMesh.examples_dir(), "GingerbreadMan.control") julia> output = generate_mesh(control_file) ``` @@ -47,8 +51,35 @@ while the 3D file `Snake.control` produces this mesh: ![snake_400px](https://user-images.githubusercontent.com/3637659/117241963-8ce0b080-ae34-11eb-9b79-d091807d9a23.png) +Examples scripts of interactive mesh generation tools are available in the +[examples/](https://github.com/trixi-framework/HOHQMesh.jl/tree/main/examples) subdirectory. +These example scripts are prefaced with the phrase `interactive_`. +There is a brief summary at the top of each `interactive` example script that describes +the mesh it will create and the features of HOHQMesh it uses. +An example script can be executed from a Julia REPL session with an `include(...)` statement, e.g., +```julia +julia> include(joinpath(HOHQMesh.examples_dir(), "interactive_outer_box_two_circles.jl")) +``` +The resulting output mesh and plot files are saved in the output directory `out` as +designated in the example script. Mesh statistics are printed to the screen. + +The interactive functionality uses [Makie.jl](https://github.com/JuliaPlots/Makie.jl/) +to visualize the boundary curves and mesh from the interactive tool. A Makie backend, such as +[GLMakie](https://github.com/JuliaPlots/GLMakie.jl/), can +be loaded in addition to HOHQMesh +```julia +julia> using Pkg; Pkg.add("GLMakie") +julia> using GLMakie +``` +Now, running the example script produces a figure in addition to the mesh and plot +files that are saved and the output of mesh statistics to the screen. + +![box_two_circles](https://user-images.githubusercontent.com/25242486/174244295-40d31df3-981e-4375-bc3a-af0a43737710.png) + +Further explanation of the interactive functionality can be found [here](@ref InteractiveTool). +Additional examples are available in the [Tutorials](@ref). -## Authors +## [Authors](@id authors-index-md) HOHQMesh.jl is maintained by the [Trixi authors](https://github.com/trixi-framework/Trixi.jl/blob/main/AUTHORS.md). Its principal developers are [Andrew Winters](https://liu.se/en/employee/andwi94) @@ -59,20 +90,12 @@ The *HOHQMesh* mesh generator itself is developed by David A. Kopriva. ## License and contributing HOHQMesh.jl is licensed under the MIT license (see [License](@ref)). *HOHQMesh* itself is also available under the MIT license. +Since HOHQMesh is an open-source project, we are very happy to accept contributions +from the community. Please refer to [Contributing](@ref) for more details. +To get in touch with the developers, +[join us on Slack](https://join.slack.com/t/trixi-framework/shared_invite/zt-sgkc6ppw-6OXJqZAD5SPjBYqLd8MU~g) +or [create an issue](https://github.com/trixi-framework/HOHQMesh.jl/issues/new). -### Preview of the documentation - -You can build the documentation of HOHQMesh.jl locally by running -```bash -julia --project=docs -e 'using Pkg; Pkg.instantiate(); include("docs/make.jl")' -``` -from the HOHQMesh.jl main directory. Then, you can look at the html files generated in -`docs/build`. -For PRs triggered from branches inside the HOHQMesh.jl main repository previews of -the new documentation are generated at `https://trixi-framework.github.io/HOHQMesh.jl/previews/PRXXX`, -where `XXX` is the number of the PR. -Note, this does not work for PRs from forks for security reasons (since anyone could otherwise push -arbitrary stuff, including malicious code). ## Acknowledgements The authors would like to thank David A. Kopriva for making the sources of diff --git a/docs/src/interactive-api.md b/docs/src/interactive-api.md new file mode 100644 index 00000000..103f150d --- /dev/null +++ b/docs/src/interactive-api.md @@ -0,0 +1,482 @@ +# API + +## Project creation and saving + +### New `Project` +``` + [Return:Project] proj = newProject(name::String, folder::String) +``` +The supplied name will be the default name of the mesh and plot files generated by HOHQMesh. The folder is +the directory in which those files will be placed. The empty project will include default `RunParameters` +and a default `SpringSmoother`, both of which can be modified later, if desired. The only thing required to +add is the background grid. + +### Opening an existing project file + +A project can be created from an existing HOHQMesh control file with +``` + [Return:Project] proj = openProject(fileName::String, folder::String) +``` +The supplied `fileName` will be the name of the project and the generated mesh and plot files will be placed +in the supplied `folder`. + +### Saving a `Project` +``` + saveProject(proj::Project) +``` +writes a control file to the folder designated when creating the new project. +It can be read in again with `openProject`. + +## Plotting a `Project` + +``` + plotProject!(proj::Project, options) +``` +The plot options are any combination of `MODEL`, `GRID`, `REFINEMENTS`, and `MESH`. +`MODEL` refers to any inner / outer boundary curves contained in the project. +`GRID` refers to the background grid, which you an view to make sure that it can resolve +the boundary curves in the model. +`REFINEMENTS` will show the placement where user defined manual refinement regions are placed. +`MESH` refers to the actual mesh of quadrilateral elements generated by HOHQMesh. +Before meshing one probably wants to view `MODEL+GRID`, and afterwards, `MODEL+MESH`. + +If the model is modified and you want to re-plot with the new values, invoke +``` + updatePlot!(proj::Project, options) +``` +but generally the plot will be updated automatically as you build the model. + +## Modifying/editing a `Project` + +### Setting the name of a `Project` + +The project name is the name under which the mesh, plot, statistics and control files will be written. +It can be changed at any time with +``` + setName!(proj::Project,name::String) +``` + +### Getting the current name of a `Project` +The project name can be fetched and printed to the screen with +``` + [Return:String] getName(proj::Project) +``` + +## Controlling the mesh generation + +### Editing the `RunParameters` + +The run parameters can be enquired and set with these getter/setter pairs: +``` + [Return:nothing] setPolynomialOrder!(proj::Project, p::Int) + [Return:Int] getPolynomialOrder(proj::Project) + [Return:nothing] setMeshFileFormat!(proj::Project, meshFileFormat::String) + [Return:String] getMeshFileFormat(proj::Project) + [Return:nothing] setPlotFileFormat!(proj::Project, plotFileFormat::String) + [Return:String] getPlotFileFormat(proj::Project) +``` + +HOHQMesh generates mesh files that contain high-order polynomial interpolations for any +curved boundaries in the model. The degree of this polynomial representation is controlled +by the above getter/setter pair. The default polynomial order is set to `5`. + +The available mesh file formats are `"ISM"`, `"ISM-V2"`, or `"ABAQUS"`. See the HOHQMesh documentation, +[Appendix A](https://trixi-framework.github.io/HOHQMesh/appendix/#appendix-a-additions-for-ism-v2) +or [Appendix E](https://trixi-framework.github.io/HOHQMesh/appendix/#appendix-e-abaqus-mesh-file-format), +as well as the Trixi.jl documentation, +[Unstructured quadrilateral mesh](https://trixi-framework.github.io/Trixi.jl/stable/meshes/unstructured_quad_mesh/) +or +[P4est-based mesh](https://trixi-framework.github.io/Trixi.jl/stable/meshes/p4est_mesh/), +for details and discussions on the latter two mesh file formats. + +The plot file (which can be viewed with something like VisIt or ParaView) format is either `"skeleton"` or `"sem"`. +The former is just a low order finite element representation of the mesh. +The latter (which is a much bigger file) includes the interior degrees of freedom. + +### Changing the output file names + +By default, the mesh, plot and stats files will be written with the name and path supplied when +`newProject` is called. They can be changed/enquired with +``` + [Return:nothing] setName!(proj::Project,name::String) + [Return:String] getName(proj::Project) + [Return:nothing] setFolder!(proj::Project,folder::String) + [Return:String] getFolder(proj::Project) +``` + +### Smoothing operations + +A default smoother is created when `newProject` is called, which sets the status to `ON`, type to +`LinearAndCrossbarSpring`, and number of iterations = 25. These are generally good enough for most purposes. +The most likely parameter to change is the number of iterations. Further details on the smoothing strategy +and how it works are available [here](https://trixi-framework.github.io/HOHQMesh/the-control-input/#the-smoother). + +To change the defaults, the smoother parameters can be set/enquired with the functions +``` + [Return:nothing] setSmoothingStatus!(proj::Project, status::String) + [Return:String] getSmoothingStatus(proj::Project) + [Return:nothing] setSmoothingType!(proj::Project, type::String) + [Return:String] getSmoothingType(proj::Project) + [Return:nothing] setSmoothingIterations!(proj::Project, iterations::Int) + [Return:Int] getSmoothingIterations(proj::Project) +``` +The smooth `status` is either "ON" or "OFF". + +To remove the smoother altogether, use +``` + [Return:nothing] removeSpringSmoother!(proj::Project) +``` + +### Adding the background grid + +There are three forms for the background grid definition, one for when there is an outer boundary, +and two for when there is not. One form of background grid **must** to be specified +after a new project has been created. +``` + [Return:nothing] addBackgroundGrid!(proj::Project, + x0::Array{Float64}, + dx::Array{Float64}, + N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, + box::Array{Float64}, + N::Array{Int}) + [Return:nothing] addBackgroundGrid!(proj::Project, + bgSize::Array{Float64}) +``` +Use one of the first two if there is no outer boundary present in the model. With the first, a rectangular +outer boundary will be created of extent `[x0[1], x0[1] + N*dx[1]]` by `[x0[2], x0[2] + N*dx[2]]`. +The second lets you set the bounding box = [top, left, bottom, right], and the number of points in each direction. +The arrays `x0`, `dx`, and `N` are all vectors `[ *, *, * ]` giving the x, y, and z components. +When an outer boundary is present use the third variant where one only need specify the desired background grid size +with the vector `bgSize`. + +### Changing the background grid + +The size of an existing background grid in a `Project` can be adjusted with +``` + [Return:nothing] setBackgroundGridSize!(proj::Project, + dx::Float64, + dy::Float64) +``` +If a plot is present it will be updated automatically. + +### Manual refinement regions + +Refinement can be specified either at a point, using the `RefinementCenter`, or along a line, +using a `RefinementLine`. You can have as many of these refinement regions as you want. +They are useful if you know regions of the solution where refinement is needed +(e.g. a wake) or in problematic areas of the geometry (e.g a sharp corner). + +To create a `RefinementCenter`, +``` + [Return:Dict{String,Any}] newRefinementCenter(name::String, + type::String, + x0::Array{Float64}, + h::Float64, + w::Float64) +``` +where `name` labels the refinement region, the `type` is either "smooth" or "sharp", +`x0` = [x, y, z] is the location of the center, `h` is the mesh size, +and `w` is the extent of the refinement region. The z component must be zero. + +Similarly, one can create a `RefinementLine`, +``` + [Return:Dict{String,Any}] newRefinementLine(name::String, + type::String, + x0::Array{Float64}, x1::Array{Float64}, + h::Float64, + w::Float64) +``` +where `x0` is the start position and `x1` is the end of the line. The `name`, `type`, `h`, and `w` +parameters are the same as for a `RefinementCenter`. + +To add a refinement region to the project, +``` + [Return:nothing] addRefinementRegion!(proj::Project, r::Dict{String,Any}) +``` + +To get a reference to a refinement region with a given name, use +``` + [Return:Dict{String,Any}] getRefinementRegion(proj::Project, name::String) +``` + +Finally, to get a list of all the refinement regions, +``` + [Return:Array{Dict{String,Any}}] array = allRefinementRegions(proj::Project) +``` + +A refinement region can be edited by using the following: +``` + [Return:nothing] setRefinementType!(r::Dict{String,Any}, type::String) + [Return:String] getRefinementType(r::Dict{String,Any}) + [Return:nothing] setRefinementLocation!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementLocation(r::Dict{String,Any}) + [Return:nothing] setRefinementGridSize!(r::Dict{String,Any}, h::Float64) + [Return:Float64] getRefinementGridSize(r::Dict{String,Any}) + [Return:nothing] setRefinementWidth!(r::Dict{String,Any}, w::Float64) + [Return:Float64] getRefinementWidth(r::Dict{String,Any}) +``` +where `r` is a dictionary returned by `newRefinementCenter!`, `newRefinementLine!`, or `getRefinementRegion`. + +To further edit a `RefinementLine`, use the methods +``` + [Return:nothing] setRefinementStart!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementStart(r::Dict{String,Any}) + [Return:nothing] setRefinementEnd!(r::Dict{String,Any}, x::Array{Float64}) + [Return:Array{Float64}] getRefinementEnd(r::Dict{String,Any}) +``` + +## Boundary curves + +The `Project` contains a model that contains information about any inner and/or outer +boundary curves that a user can add to define a domain to be meshed. Each curve is defined as a +"chain" that can be built from multiple connected curves. More details on boundary curves and +HOHQMesh can be found [here](https://trixi-framework.github.io/HOHQMesh/the-model/). + +The domain can have a single outer boundary chain and an arbitrary number of inner boundary chains. + +The orientation of any curve chains must be counter-clockwise. +This orientation is automatically checked in `generate_mesh` and a warning is thrown if +a user attempts to connect the curve chain in an invalid way. + +See the tutorial [Creating and editing curves](@ref) for a demonstration of defining, +constructing, and removing curves from a `Project`. + +### Defining curves + +Four curve types can be added to the outer and inner boundary curve chains. They are + +- Parametric equations +- Cubic Splines +- Lines defined by their end points +- Circular arcs + +#### Parametric equations + +Creating a new curve equation +``` + [Return:Dict{String,Any}] newParametricEquationCurve(name::String, + xEqn::String, + yEqn::String, + zEqn::String = "z(t) = 0.0") +``` +Returns a new set of parametric equation. Equations must be of the form +``` + () = ... +``` +The name of the function, and the argument are arbitrary. The equation can be any legitimate equation. +The constant `pi` is defined for use. Exponentiation is done with `^`. All number literals are interpreted +as floating point numbers. + +Example: +```julia + xEqn = "x(t) = 4*cos(2*pi*t) - 0.6*cos(8*pi*t)^3" + yEqn = "y(t) = 4*sin(2*pi*t) - 0.5*sin(11*pi*t)^2" + zEqn = "z(t) = 0.0" + blob = newParametricEquationCurve("Blob", xEqn, yEqn, zEqn) +``` +The z-Equation is optional, but for now must define zero for z by default. + +#### Cubic spline curve + +A cubic spline is defined by an array of knots, $t_j$, $x_j$, $y_j$, $z_j$. +It can either be supplied by a data file whose first line is the number of knots, and succeeding lines define +the $t$, $x$, $y$, $z$ values, e.g. +``` + 9 + 0.000000000000000 -3.50000000000000 3.50000000000000 0.0 + 3.846153846153846E-002 -3.20000000000000 5.00000000000 0.0 + 7.692307692307693E-002 -2.00000000000000 6.00000000000 0.0 + 0.769230769230769 0.000000000000000 -1.00000000000000 0.0 + 0.807692307692308 -1.00000000000000 -1.00000000000000 0.0 + 0.846153846153846 -2.00000000000000 -0.800000000000000 0.0 + 0.884615384615385 -2.50000000000000 0.000000000000000 0.0 + 0.923076923076923 -3.00000000000000 1.00000000000000 0.0 + 1.00000000000000 -3.50000000000000 3.50000000000000 0.0 +``` +or by constructing the required `nKnots` x `4` array and supplying it to the new procedure. The respective constructors +for a spline curve are +``` + [Return:Dict{String,Any}] newSplineCurve(name::String, + dataFile::String) + [Return:Dict{String,Any}] newSplineCurve(name::String, + nKnots::Int, + data::Matrix{Float64}) +``` +If the spline curve is to be closed. The last data point must be the same as the first. + +Example: +```julia + spline_data = [ [0.0 1.75 -1.0 0.0] + [0.25 2.1 -0.5 0.0] + [0.5 2.7 -1.0 0.0] + [0.75 0.6 -2.0 0.0] + [1.0 1.75 -1.0 0.0] ] + ex_spline = newSplineCurve("small_spline", 5, spline_data) +``` + +#### Line defined by end points + +A straight line is constructed with +``` + [Return:Dict{String,Any}] newEndPointsLineCurve(name::String, + xStart::Array{Float64}, + xEnd::Array{Float64}) +``` +The `xStart` and `xEnd` are arrays of the form [x, y, z]. The `z` component should be zero and for now is ignored. + +Example: +```julia + line1 = newEndPointsLineCurve("line_segment", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) +``` + +#### Circular arc +``` + [Return:Dict{String,Any}] newCircularArcCurve(name::String, + center::Array{Float64}, + radius::Float64, + startAngle::Float64, + endAngle::Float64, + units::String) +``` +The center is an array of the form [x, y, z]. The units argument defines the start and end angle units. +It is either "degrees" or "radians". That argument is optional, and defaults to "degrees". + +Example: +```julia + halfCircle = newCircularArcCurve("Dome", [0.0, 0.0, 0.0], 1.0, 0.0, 180.0, "degrees") +``` + +### Adding and removing outer and inner boundaries + +1. Adding an outer boundary curve + + Using the curve creation routines described above, create curves counter-clockwise along the outer boundary + and add them to the outer boundary curve using + + ``` + [Return:nothing] addCurveToOuterBoundary!(proj::Project, + crv::Dict{String,Any}) + ``` + + `crv` is the dictionary that represents the curve. + + Example: + + ```julia + circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "degrees") + addCurveToOuterBoundary!(p, circ) + ``` + +2. Adding an inner boundary curve + + The syntax is analogous to the creation of an outer boundary curve. Once interior curves are defined + they can be added to chain, again in counter-clockwise orientation. Note that the individual pieces + of the curve are given a name. The entire chain is also given a name. + + ``` + [Return:nothing] addCurveToInnerBoundary!(proj::Project, + crv::Dict{String,Any}, + chainName::String) + ``` + + Example: + + ```julia + line1 = newEndPointsLineCurve("line_segment", [0.0, -3.0, 0.0], [1.0, 0.0, 0.0]) + addCurveToInnerBoundary!(p, line1, "interior_curve") + ``` + + To edit curves they can be accessed by the name: + + ``` + [Return:Dict{String,Any}] getInnerBoundaryCurve(proj::Project, + curveName::String, + chainName::String) + [Return:Dict{String,Any}] getOuterBoundaryCurveWithName(proj::Project, + name::String) + ``` + +3. Deleting boundary curves + + The entire outer boundary or an entire inner boundary can be removed from the project. + + ``` + [Return:nothing] removeOuterBoundary!(proj::Project) + [Return:nothing] removeInnerBoundary!(proj::Project, chainName::String) + ``` + + Alternatively, individual pieces of the boundary curve chains can be removed. + + ``` + [Return:nothing] removeOuterBoundaryCurveWithName!(proj::Project, name::String) + [Return:nothing] removeInnerBoundaryCurve!(proj::Project, + name::String, + chainName::String) + ``` + + As in HOHQMesh the project can have only one outer boundary chain, so the removal does not + require a specific `chainName`. + +### Editing curves + +You can determine the type of a curve by +``` + [Return:String] getCurveType(crv::Dict{String,Any}) +``` + +For any of the curves, their name can be changed by +``` + setCurveName!(crv::Dict{String,Any}, name::String) +``` +and checked by +``` + getCurveName(crv::Dict{String,Any}) +``` + +Otherwise there are special functions to change the parameters of curves +``` + [Return:nothing] setXEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setYEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setZEqn!(crv::Dict{String,Any}, eqn::String) + [Return:nothing] setStartPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setEndPoint!(crv::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcUnits!(arc::Dict{String,Any}, units::String) + [Return:nothing] setArcCenter!(arc::Dict{String,Any}, point::Array{Float64}) + [Return:nothing] setArcStartAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcEndAngle!(arc::Dict{String,Any}, angle::Float64) + [Return:nothing] setArcRadius!(arc::Dict{String,Any}, radius::Float64) + + [Return:String] getXEqn(crv::Dict{String,Any}) + [Return:String] getYEqn(crv::Dict{String,Any}) + [Return:String] getZEqn(crv::Dict{String,Any}) + [Return:Array{Float64}] getStartPoint(crv::Dict{String,Any}) + [Return:Array{Float64}] getEndPoint(crv::Dict{String,Any}) + [Return:String] getArcUnits(arc::Dict{String,Any}) + [Return:Array{Float64}] getArcCenter(arc::Dict{String,Any}) + [Return:Float64] getArcStartAngle(arc::Dict{String,Any}) + [Return:Float64] getArcEndAngle(arc::Dict{String,Any}) + [Return:Float64] getArcRadius(arc::Dict{String,Any}) +``` + +## Undo/redo + +The interactive mesh functionality has unlimited undo/redo for most actions. + +In interactive mode, actions can be undone by the commands +``` + [Return:String] undo() + [Return:String] redo() +``` +where the return string contains the name of the action performed. + +To find out what the next actions are, use +``` + [Return:String] undoActionName() + [Return:String] redoActionName() +``` + +Finally, to clear the undo stack, use +``` + [Return:nothing] clearUndoRedo() +``` \ No newline at end of file diff --git a/docs/src/interactive_overview.md b/docs/src/interactive_overview.md new file mode 100644 index 00000000..3f873d5c --- /dev/null +++ b/docs/src/interactive_overview.md @@ -0,0 +1,152 @@ +# [Overview](@id InteractiveTool) + +The interactive functionality is an API to generate a quadrilateral (future: hexahedral) +mesh using Julia. +It serves as a front end to the HOHQMesh program, and is designed to let one build a +meshing project interactively while graphically displaying the results. + +Several scripts are available in the `examples` folder +to get you started. These example scripts follow the naming convention of `interactive_*` where +the phrase interactive indicates their association with this API and then trailing information +will indicate what that script demonstrates. For instance, the file `interactive_splines.jl` +provides an interactive project that creates an manipulates splines for the inner boundaries before +generating the mesh. + +Below we provide a broad overview of the interactive mesh workflow. Further clarification on +this workflow is provided in the [Guided tour](@ref). Several [Tutorials](@ref) +are also available to demonstrate this functionality. + +## Workflow and basic moves + +The order of the workflow and basic moves follow a logical pattern: The project must be created first. +Curves can be added at any time. The background grid can be added any time to the project. +A mesh is usually generated after the model (curves) and background grid are completed. + +To generate a mesh interactively you + +1. Create a project with a user given `projectName` and `folder` where any generated files are to be saved + + ``` + p = newProject(, ) + ``` + + Both of these input arguments are strings. + +2. Create inner and outer boundary curves from the available types + + ``` + c = newEndPointsLineCurve(, startLocation [x, y, z], endLocation [x, y, z]) *Straight Line* + c = newCircularArcCurve(, center [x, y, z], radius, startAngle, endAngle, units = "degrees" or "radians") *Circular Arc* + c = newParametricEquationCurve(, xEqn, yEqn, zEqn) *Parametric equation* + c = newSplineCurve(, dataFile) *Spline with data from a file* + c = newSpline(, nKnots, knotsMatrix) *Spline with given knot values* + ``` + + See [Defining curves](@ref) for further details on the different curve type currently supported by HOHQMesh. + + The generic name for each of these curve creation methods is `new!`. The generic can be used instead of the longer descriptive name to save typing during interactive sessions, if desired. + +3. Add curves to build the model to see what you have added, + + ``` + addOuterBoundaryCurve!(p, ) *Add outer boundary curve* + addInnerBoundaryCurve!(p, , ) *Add curve to an inner boundary* + ``` + + For a single inner / outer boundary curve the command above directly adds the curve into the `Project`. + If the inner / outer boundary curve is a chain of multiple curves then they must be added to the `Project` + in an order which yields a closed curves with counter-clockwise orientation. + See the [Guided tour](@ref) for an example of a chain of curves. + + Curves can be added by using the generic `add!` function instead of the longer descriptive + name to save typing during interactive sessions, if desired. + +4. Visualize the project's model, if desired + + ``` + plotProject!(p, MODEL) + ``` + + Plots are updated in response to user interactions. However, to update the plot at any time, use + + ``` + updatePlot!(p, options) + ``` + + Options are `MODEL`, `GRID`, `MESH`, and `REFINEMENTS`. To plot combinations, sum the options, e.g. + `MODEL`+`GRID` or `MODEL`+`MESH`. You normally are not interested in the background grid once + the mesh is generated. + + !!! note "Visualization requirement" + The interactive functionality uses [Makie.jl](https://github.com/JuliaPlots/Makie.jl/) + to visualize the `Project` information. Therefore, in addition to HOHQMesh.jl a user must + load a Makie backend (for example, [GLMakie](https://github.com/JuliaPlots/GLMakie.jl/) or + [CairoMakie](https://github.com/JuliaPlots/CairoMakie.jl)) if visualization is desired. + +5. Set the background grid + + When no outer boundary curve is present, the background grid can be set with + + ``` + addBackgroundGrid!(p, lower left [x,y,z], spacing [dx,dy,dz], num Intervals [nX,nY,nZ]) + ``` + + Or + + ``` + addBackgroundGrid!(p, [top value, left value, bottom value, right value], num Intervals [nX,nY,nZ]) + ``` + + The first method creates the rectangular boundary with extent `[x0[1], x0[1] + N*dx[1]]` by + `[x0[2], x0[2] + N*dx[2]]`. The second method sets a rectangular bounding box with extent + [top value, left value, bottom value, right value] and the number of elements in each direction. + The first exists for historical reasons; the second is probably the easiest to use. + + When an outer boundary is present the background grid can be set as + + ``` + addBackgroundGrid!(p, [dx, dy, dz]) + ``` + + where the spacing controls the number of elements in each direction. + + !!! note "Background grid" + A background grid is required by HOHQMesh. If one is not present in the `Project` + and a user attempts to generate the mesh a warning is thrown. + +6. Adjust meshing parameters, if desired. For instance, one can adjust the polynomial + `order` in the `Project` for any curved boundaries by + + ``` + setPolynomialOrder!(p, order) + ``` + + The background grid size can be adjusted where we can set the grid size in the x and y directions, + `dx` and `dy`, can be set separately + + ``` + setBackgroundGridSize!(p, 0.5, 0.25) + ``` + + See [Controlling the mesh generation](@ref) for details on adjusting parameters already present + in the `Project`. + +7. Generate the mesh + + ``` + generate_mesh(p) + ``` + + The mesh file will be saved in `` with the name `.mesh`. A HOHQMesh control file + is automatically created from the contents of the `Project` and is also saved in that folder + with the name `.control`. This control file can be read in again later and modified, + remeshed, etc. The function `generate_mesh` will print the mesh information and statistics, and will + plot the mesh as in the figure above, if a plot is otherwise visible. + If not, it can always be plotted with the `plotProject!` command. + +## Advanced + +All objects and information contained in the variable type `Project` are actually dictionaries of type `Dict{String, Any}`. +Since Julia is not an object oriented language, the parameters and other parts of these internal dictionaries +can be accessed and edited directly by key and value. +However, if you do that, then certain features like `undo`/`redo` and automatic plot updating **will not work**. \ No newline at end of file diff --git a/docs/src/testing.md b/docs/src/testing.md new file mode 100644 index 00000000..937a521d --- /dev/null +++ b/docs/src/testing.md @@ -0,0 +1,85 @@ +# Testing + +During the development of HOHQMesh and its interactive functionality, we rely on +[continuous testing](https://en.wikipedia.org/wiki/Continuous_testing) to ensure +that modifications or new features do not break existing +functionality or add other errors. In the main +[HOHQMesh](https://github.com/trixi-framework/HOHQMesh.jl) repository, this is facilitated by +[GitHub Actions](https://docs.github.com/en/free-pro-team@latest/actions), +which allows to run tests automatically upon certain events. When, how, and what +is tested by GitHub Actions is controlled by the workflow file +[`.github/workflows/ci.yml`](https://github.com/trixi-framework/HOHQMesh.jl/blob/main/.github/workflows/ci.yml). +In Trixi and its related repositories, tests are triggered by +* each `git push` to `main` and +* each `git push` to any pull request. +Besides checking functionality, we also analyze the [Test coverage](@ref) to +ensure that we do not miss important parts during testing. + +!!! note "Test and coverage requirements" + Before merging a pull request (PR) to `main`, we require that + * the code passes all functional tests + * code coverage does not decrease. + + +## Testing setup +The entry point for all testing is the file +[`test/runtests.jl`](https://github.com/trixi-framework/HOHQMesh.jl/blob/main/test/runtests.jl), +which is run by the automated tests and which can be triggered manually by +executing +```julia +julia> using Pkg; Pkg.test("HOHQMesh") +``` +in the REPL. Since there already exist many tests, we have split them up into +multiple files in the `test` directory to allow for faster testing of individual +parts of the code. +Thus in addition to performing all tests, you can also just `include` one of the +files named `test_xxx.jl` to run only a specific subset, e.g., +```julia +julia> # Run all test for the interactive Curve API + include(joinpath("test", "test_curve.jl")) +``` + + +## Adding new tests +We use Julia's built-in [unit testing capabilities](https://docs.julialang.org/en/v1/stdlib/Test/) +to configure tests. In general, newly added code must be covered by at least one +test, and all new scripts added to the `examples/` directory must be used at +least once during testing. New tests should be added to the corresponding +`test/test_xxx.jl` file, e.g., a test involving visualization capabilities +would go into +[`test/test_visualization.jl`](add link). +Please study one of the existing tests and stay consistent to the current style +when creating new tests. + +Since we want to test as much as possible, we have a lot of tests and +frequently create new ones. Therefore, new tests should be as +short as reasonably possible, i.e., without being too insensitive to pick up +changes or errors in the code. + +When you add new tests, please check whether all CI jobs still take approximately +the same time. If the job where you added new tests takes much longer than +everything else, please consider moving some tests from one job to another +(or report this incident and ask the main developers for help). + +!!! note "Test duration" + As a general rule, tests should last **no more than 10 seconds** when run + with a single thread and after compilation (i.e., excluding the first run). + + +## Test coverage +In addition to ensuring that the code produces the expected results, the +automated tests also record the +[code coverage](https://en.wikipedia.org/wiki/Code_coverage). The resulting +coverage reports, i.e., which lines of code were executed by at least one test +and are thus considered "covered" by testing, are automatically uploaded to +[Coveralls](https://coveralls.io) for easy analysis. Typically, you see a number +of Coveralls results at the bottom of each pull request: One for each parallel +job (see [Testing setup](@ref)), which can usually be ignored since they only +cover parts of the code by definition, and a cumulative coverage result named +`coverage/coveralls`. The "Details" link takes you to a detailed report on +which lines of code are covered by tests, which ones are missed, and especially +which *new* lines the pull requests adds to HOHQMesh's code base that are not yet +covered by testing. +!!! note "Coverage requirements" + In general, we require pull requests to *not decrease* the overall + test coverage percentage in `main`, with a **hard lower bound of 97%**. diff --git a/docs/src/tutorials/create_edit_curves.md b/docs/src/tutorials/create_edit_curves.md new file mode 100644 index 00000000..7afda25c --- /dev/null +++ b/docs/src/tutorials/create_edit_curves.md @@ -0,0 +1,527 @@ +# Creating and editing curves + +The purpose of this tutorial is to demonstrate how to inner and outer boundary +curve chains. +By a "chain" we mean a closed curve that is composed of multiple pieces. +Each chain can be a combination of different curve types, e.g., a circular +arc can connect to a spline. +It also shows how to modify, remove, and add new pieces to an existing curve chain. +The `undo` and `redo` capabilities of the interactive mesh tool are briefly discussed. +The outer and inner boundary curves, background grid as well as the mesh +will be visualized for quality inspection. + +### Synopsis + +This tutorial demonstrates how to: +* Create and edit an outer boundary chain. +* Create and edit an inner boundary chain. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Discuss undo / redo capabilities. +* Construct and add parametric spline curves. +* Construct and add a curve from parametric equations. +* Construct and add straight line segments. +* Construct and add circular arc segments. + +## Initialization + +From a Julia REPL we load the HOHQMesh package as well as +[GLMakie](https://github.com/JuliaPlots/GLMakie.jl/), a backend of +[Makie.jl](https://github.com/JuliaPlots/Makie.jl/), to visualize the +curves, mesh, etc. from the interactive tool. +```julia +julia> using GLMakie, HOHQMesh +``` +Now we are ready to interactively generate unstructured quadrilateral meshes! + +We create a new project with the name `"sandbox"` and +assign `"out"` to be the folder where any output files from the mesh generation process +will be saved. By default, the output files created by HOHQMesh will carry the same name +as the project. For example, the resulting HOHQMesh control file from this tutorial +will be named `sandbox.control`. +If the folder `out` does not exist, it will be created automatically in +the current file path. +```julia +sandbox_project = newProject("sandbox", "out") +``` + +## Add the outer boundary chain + +We first create the outer boundary curve chain that is composed of three pieces +1. Straight line segment from $(0, -7)$ to $(5, 3)$. +2. Half-circle arc of radius $r=5$ centered at $(0, 3)$. +3. Straight line segment from $(-5, 3)$ to $(0, -7)$. + +Each segment of the curve is created separately. The straight line segments are +made with the function `newEndPointsLineCurve` and given unique names: +```julia +outer_line1 = newEndPointsLineCurve("Line1", # curve name + [0.0, -7.0, 0.0], # start point + [5.0, 3.0, 0.0]) # end point + +outer_line2 = newEndPointsLineCurve("Line2", # curve name + [-5.0, 3.0, 0.0], # start point + [0.0, -7.0, 0.0]) # end point +``` +To create the circle arc we use the function `newCircularArcCurve` where +we specify a name for the curve as well as the radius and center of the circle. +The arc can have an arbitrary length dictated by the start and end angle, e.g., for +a half-circle we take the angle to vary from $0$ to $180$ degrees. +```julia +outer_arc = newCircularArcCurve("Arc", # curve name + [0.0, 3.0, 0.0], # center + 5.0, # radius + 0.0, # start angle + 180.0, # end angle + "degrees") # units for angle +``` +We use `"degrees"` to set the angle bounds, but `"radians"` can also be used. +The name of the curve stored in the dictionary `outer_arc` is assigned to be `"Arc"`. + +The curve names `"Line1"`, `"Line2"`, and `"Arc"` are the labels that +HOHQMesh will give to these boundary curve segments in the resulting mesh file. + +The three curve segments stored in the variables `outer_line1`, `outer_line2`, and `outer_arc` +are then added to the `sandbox_project` with a counter-clockwise +orientation as required by HOHQMesh. +```julia +addCurveToOuterBoundary!(sandbox_project, outer_line1) +addCurveToOuterBoundary!(sandbox_project, outer_arc) +addCurveToOuterBoundary!(sandbox_project, outer_line2) +``` + +## Add a background grid + +HOHQMesh requires a background grid for the mesh generation process. This background grid sets +the base resolution of the desired mesh. HOHQMesh will automatically subdivide from this background +grid near sharp features of any curved boundaries. + +For a domain bounded by an outer boundary curve, this background grid is set by indicating +the desired element size in the $x$ and $y$ directions. +To start, we set the background grid for `sandbox_project` +to have elements with side length one in each direction +```julia +addBackgroundGrid!(sandbox_project, [1.0, 1.0, 0.0]) +``` + +We visualize the outer boundary curve chain and background grid with the following +```julia +plotProject!(sandbox_project, MODEL+GRID) +``` +Here, we take the sum of the keywords `MODEL` and `GRID` in order to simultaneously visualize +the outer boundary and background grid. The resulting plot is given below. The chain of outer boundary +curves is called `"Outer"` and it contains three curve segments `"Line1"`, `"Arc"`, and `"Line2"` +labeled in the figure by `O.1`, `O.2`, and `O.3`, respectively. + +![background_grid](https://user-images.githubusercontent.com/25242486/175062627-a87ed6e1-ce68-4ef4-a178-96b1ccceff0a.png) + +## Edit the outer boundary chain + +Suppose that the domain boundary requires a curved segment instead of the straight line +`"Line2"`. We will replace this line segment in the outer boundary chain with a cubic +spline. + +First, we remove the `"Line2"` curve from the `"Outer"` chain with the command +```julia +removeOuterBoundaryCurveWithName!(sandbox_project, "Line2") +``` +!!! tip "Outer curve removal" + Alternatively, we can remove the curve `"Line2"` using its index in the `"Outer"` boundary + chain. + ```julia + removeOuterBoundaryCurveAtIndex!(sandbox_project, 3) + ``` + This removal strategy is useful when the curves in the boundary chain do not have unique + names. Be aware that when curves are removed from a chain it is possible that + the indexing of the remaining curves changes. +The plot automatically updates and we see that the outer boundary is open and contains +two segments: `"Line1"` and `"Arc"`. + +![outer_removal](https://user-images.githubusercontent.com/25242486/175062663-8a0e3a4f-c444-4302-a35b-7565095ab78a.png) + +Next, we create a parametric cubic spline curve from a given set of data points. In order to make a +closed outer boundary chain the cubic spline must begin at the endpoint of the curve `"Arc"` +and end at the first point of the curve `"Line1"`. This ensures that the new spline curve +connects into the boundary curve chain with the correct orientation. To create a parametric +spline curve we directly provide data points in the code. These points take the form +`[t, x, y, z]` where `t` is the parameter variable that varies between $0$ and $1$. +The spline curve constructor `newSplineCurve` also takes the number of points as an +input argument. +```julia +spline_data = [ [0.0 -5.0 3.0 0.0] + [0.25 -2.0 1.0 0.0] + [0.5 -4.0 0.5 0.0] + [0.75 -2.0 -3.0 0.0] + [1.0 0.0 -7.0 0.0] ] +outer_spline = newSplineCurve("Spline", 5, spline_data) +``` +Now we add the spline curve `outer_spline` into the `sandbox_project`. +```julia +addCurveToOuterBoundary!(sandbox_project, outer_spline) +``` +The figure updates automatically to display the `"Outer"` boundary chain +with the new `"Spline"` curve labeled `O.3`. + +![outer_spline](https://user-images.githubusercontent.com/25242486/175062706-6d12840c-f5fa-49e6-ad18-d46d643dd3d8.png) + +## Add an inner boundary chain + +We create a pill shaped inner boundary curve chain composed of four pieces +1. Straight line segment from $(1, 5)$ to $(1, 3)$. +2. Half-circle arc of radius $r=1$ centered at $(0, 3)$. +3. Straight line segment from $(-1, 3)$ to $(-1, 5)$. +4. Half-circle arc of radius $r=1$ centered at $(0, 5)$. + +Similar to the construction of the `"Outer"` boundary chain, each segment of +this inner boundary chain is created separately. The straight line segments are +made with the function `newEndPointsLineCurve` and given unique names: +```julia +inner_line1 = newEndPointsLineCurve("Line1", # curve name + [1.0, 5.0, 0.0], # start point + [1.0, 3.0, 0.0]) # end point + +inner_line2 = newEndPointsLineCurve("Line2", # curve name + [-1.0, 3.0, 0.0], # start point + [-1.0, 5.0, 0.0]) # end point +``` +To create the circle arcs we use the function `newCircularArcCurve` where +we specify a name for the curve as well as the radius and center of the circle. +In order to create an inner curve chain with counter-clockwise orientation the +angle for the bottom half-circle arc centered at $(0, 3)$ varies from $0$ to $-180$ +degrees. The top half-circle arc centered at $(0, 5)$ has an angle that varies from +$180$ to $0$ degrees. The construction of the two circle arcs are +```julia +inner_bottom_arc = newCircularArcCurve("BottomArc", # curve name + [0.0, 3.0, 0.0], # center + 1.0, # radius + 0.0, # start angle + -pi, # end angle + "radians") # units for angle + +inner_top_arc = newCircularArcCurve("TopArc", # curve name + [0.0, 5.0, 0.0], # center + 1.0, # radius + 180.0, # start angle + 0.0, # end angle + "degrees") # units for angle +``` +Note, we use `"radians"` to set the angle bounds for `inner_bottom_arc` and `"degrees"` +for the angle bounds of `inner_top_arc`. + +The curve names `"Line1"`, `"Line2"`, `"BottomArc"`, and `"TopArc"` are the labels that +HOHQMesh will give to these inner boundary curve segments in the resulting mesh file. + +The four curve segments stored in the variables `inner_line1`, `inner_line2`, +`inner_bottom_arc` and `outer_arc` are added to the `sandbox_project` in counter-clockwise order as required by HOHQMesh. +```julia +addCurveToInnerBoundary!(sandbox_project, inner_line1, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_bottom_arc, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_line2, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_top_arc, "inner") +``` +This inner boundary chain name `"inner"` is used internally by HOHQMesh. The visualization +of the background grid automatically detects that curves have been added to the +`sandbox_project` and the plot is updated, as shown below. The chain for the inner boundary curve chain is called `inner` and it contains a four curve segments +`"Line1"`, `"BottomArc"`, `"Line2"`, and `"TopArc"` labeled in the figure by +`1.1`, `1.2`, `1.3`, and `1.4`, respectively. + +![inner_pill](https://user-images.githubusercontent.com/25242486/175062834-91aae24d-167d-4d0f-8d39-887ab189081b.png) + +## Generate the mesh + +We next generate the mesh from the information contained in the `sandbox_project`. +This will output the following files to the `out` folder: + +* `sandbox.control`: A HOHQMesh control file for the current project. +* `sandbox.tec`: A TecPlot formatted file to visualize the mesh with other software, e.g., [ParaView](https://www.paraview.org/). +* `sandbox.mesh`: A mesh file with format `ISM-V2` (the default format). + +To do this we execute the command +```julia +generate_mesh(sandbox_project) + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 8.7928000000000006E-002 + Number of nodes = 513 + Number of Edges = 933 + Number of Elements = 422 + Number of Subdivisions = 7 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.00003020 1.17336756 0.18813064 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.00984888 2.32321419 1.31488869 1.00000000 999.99900000 1.00000000 + Condition 1.00041121 2.42894151 1.21101797 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.01674110 3.74861238 1.59495734 1.00000000 4.00000000 1.00000000 + Jacobian 0.00001734 1.13821390 0.14136293 0.00000000 999.99900000 1.00000000 + Minimum Angle 32.20087774 89.35157729 68.75755243 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.60787193 152.53515465 113.36966060 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +The call to `generate_mesh` also prints mesh quality statistics to the screen +and updates the visualization. +The background grid is *removed* from the visualization when the mesh is generated. + +!!! note "Mesh visualization" + Currently, only the "skeleton" of the mesh is visualized. Thus, the high-order curved boundary information + is not seen in the plot but this information **is present** in the generated mesh file. + +![initial_mesh](https://user-images.githubusercontent.com/25242486/175062901-4f1280ae-9830-4ab3-bee2-76f895b03cbb.png) + +## Delete the existing mesh + +In preparation of edits we will make to the inner boundary chain we remove the current mesh from the plot +and re-plot the model curves and background grid. +Note, this step is not required, but it helps avoid confusion when editing several curves. +```julia +remove_mesh!(sandbox_project) +updatePlot!(sandbox_project, MODEL+GRID) +``` +Additionally, the `remove_mesh!` command deletes the mesh information from the `sandbox_project` +and `sandbox.mesh` from the `out` folder. However, the `sandbox.control` and `sandbox.tec` files +are still present in `out` directory. + +## Edit an inner boundary chain + +Suppose that the inner boundary actually requires a curved segment instead of the +straight line `"Line1"`. We will replace this line segment in the inner boundary chain +with an oscillating segment construct from a set of parametric equations. In doing so, +it will also be necessary to remove the `BottomArc` and replace it with a new, wider +circular arc segment. + +We remove the `"Line1"` curve from the `inner` chain with the command +```julia +removeInnerBoundaryCurve!(sandbox_project, "Line1", "inner") +``` +!!! tip "Inner curve removal" + Alternatively, we can remove the curve `"Line1"` using its index in the `inner` boundary + chain. + ```julia + removeInnerBoundaryCurveAtIndex!(sandbox_project, 1, "inner") + ``` + This removal strategy is useful when the curves in the boundary chain do not have unique + names. Be aware that when curves are removed from a chain it is possible that + the indexing of the remaining curves changes. +With either removal strategy, the plot automatically updates. We see that the +inner boundary is open and contains three segments: `"BottomArc"`, `"Line2"`, and `"TopArc"`. +Note that the index of the remaining curves has changed as shown below. + +![inner_removal](https://user-images.githubusercontent.com/25242486/175062997-6f60b3e3-b9eb-4f6b-8062-5b17de0cca2c.png) + +!!! note "Brief note about undo / redo" + The interactive functionality (globally) carries an operation stack of actions that can be undone + (or redone) as the case may be. We can query and print to the REPL the top of the + undo stack with `undoActionName`. + ```julia + undoActionName() + "Remove Inner Boundary Curve" + ``` + We can undo the removal of the `"Line1"` curve with `undo` + ```julia + undo() + "Undo Remove Inner Boundary Curve" + ``` + In addition to reinstating `"Line1"` into the `sandbox_project`, this undo + prints the action that was undone to the REPL and will update the figure. + + Analogously, there is a redo operation stack. We query and print to the REPL the top + the redo stack with `redoActionName` and can use `redo` to perform + the operation. + +The new inner curve segment will be an oscillating line given by the +parametric equations +```math + \begin{aligned} + x(t) &= t + 1,\\[0.2cm] + y(t) &= -2t + 5 - \frac{3}{2} \cos(\pi t) \sin(\pi t),\\[0.2cm] + z(t) &= 0 + \end{aligned} + \qquad + t\in[0,1] +``` +Parametric equations in HOHQMesh can be any legitimate equation and use intrinsic functions +available in Fortran, e.g., $\sin$, $\cos$, exp. +The constant `pi` is available for use. +The following commands create a new curve for the parametric equations above +```julia +xEqn = "x(t) = t + 1" +yEqn = "y(t) = -2 * t + 5 - 1.5 * cos(pi * t) * sin(pi * t)" +zEqn = "z(t) = 0.0" +inner_eqn = newParametricEquationCurve("wiggleLine", xEqn, yEqn, zEqn) +``` +The name of this new curve is assigned to be `"wiggleLine"`. +We add this new curve to the `"inner"` chain. +```julia +addCurveToInnerBoundary!(sandbox_project, inner_eqn, "inner") +``` +The automatically updated figure now shows: + +![inner_open_chain](https://user-images.githubusercontent.com/25242486/175063103-e8eda78c-b0d9-4229-9383-5582845d5f81.png) + +We see from the figure that this parametric equation curve starts at the point $(1,5)$ +and, therefore, matches the end point of the existing curve `"TopArc"` present +in the `"inner"` chain. However, the +parametric equation curve ends at the point $(2,3)$ which **does not** match +the `"BottomArc"` curve. So, the inner boundary chain remains open. + +!!! warning "Attempt to generate a mesh with an open curve chain" + An open curve chain is **invalid** in HOHQMesh. All inner and/or outer curve chains + must be closed. If we attempt to send a project that contains an open + curve chain to `generate_mesh` a warning is thrown and no mesh or output files + are generated. + +To create a closed boundary curve we must remove the `"BottomArc"` curve and replace it +with a wider half-circle arc segment. This new half-circle arc must start at the point +$(2, 3)$ and end at the point $(-1, 3)$ to close the inner chain **and** guarantee the +chain is oriented counter-clockwise. So, we first remove the `"BottomArc"` from the `"inner"` +chain. +```julia +removeInnerBoundaryCurve!(sandbox_project, "BottomArc", "inner") +``` +The figure updates to display the `"inner"` curve chain with three segments. +Note that the inner curve chain indexing has, again, been automatically adjusted. + +![inner_remove_arc](https://user-images.githubusercontent.com/25242486/175063146-9475697a-3aa8-42c1-abdb-713343c6b8f7.png) + +A half-circle arc that joins the points $(2, 3)$ and $(-1, 3)$ has a radius $r=1.5$, is +centered at $(0.5, 3)$ and has an angle that vaires from $0$ to $-180$. +We construct this circle arc and directly add it to the `sandbox_project`. +```julia +new_bottom_arc = newCircularArcCurve("wideBottomArc", # curve name + [0.5, 3.0, 0.0], # center + 1.5, # radius + 0.0, # start angle + -pi, # end angle + "radians") # units for angle +addCurveToInnerBoundary!(sandbox_project, new_bottom_arc, "inner") +``` +The updated plot now gives the modified, closed inner curve chain that now contains +four curve segments `"Line2"`, `"TopArc"`, `"wiggleLine"`, and `"wideBottomArc"` labeled +in the figure by `1.1`, `1.2`, `1.3`, and `1.4`, respectively. + +![inner_modified](https://user-images.githubusercontent.com/25242486/175063184-9c2d1204-cdcd-4a33-88bd-d73e7183b3d6.png) + +## Regenerate the mesh + +With the modifications to the inner curve chain complete we can regenerate the mesh. +This will create a new `sandbox.mesh` file and overwrite the existing `sandbox.control` and `sandbox.tec` files in the `out` directory. +```julia +generate_mesh(sandbox_project) + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 0.13299600000000000 + Number of nodes = 714 + Number of Edges = 1308 + Number of Elements = 596 + Number of Subdivisions = 7 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.00003020 1.15662678 0.12823840 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.01082600 3.14765817 1.34292128 1.00000000 999.99900000 1.00000000 + Condition 1.00037252 2.59936116 1.22903490 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.02724726 3.74861238 1.64807401 1.00000000 4.00000000 1.00000000 + Jacobian 0.00001734 1.13150266 0.09438571 0.00000000 999.99900000 1.00000000 + Minimum Angle 31.88018513 89.33451932 67.86550651 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.43850948 157.31718198 114.36070355 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +The visualization updates automatically and the background grid is *removed* after when the mesh is generated. + +![inner_modified](https://user-images.githubusercontent.com/25242486/175063283-b60d8985-0fce-4010-90c5-5a924883a895.png) + +Inspecting the mesh we see that the automatic subdivision in HOHQMesh does well to capture the sharp corners and fine features of the curved inner and outer boundaries. For example, we zoom +into sharp corner at the bottom of the domain and see that, although small, the elements in this +region maintain a good quadrilateral shape. + +![zoom_corner](https://user-images.githubusercontent.com/25242486/175063320-57d42322-2d0e-4e69-b177-ab40d6a8df3d.png) + +## Summary + +In this tutorial we demonstrated how to: +* Create and edit an outer boundary chain. +* Create and edit an inner boundary chain. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Discuss undo / redo capabilities. +* Construct and add parametric spline curves. +* Construct and add a curve from parametric equations. +* Construct and add straight line segments. +* Construct and add circular arc segments. + +For completeness, we include a script with all the commands to generate the mesh displayed in the final image. +Note, we **do not** include the plotting in this script. +```julia +# Interactive mesh with modified outer and inner curve chains +# +# Create inner / outer boundary chains composed of the four +# available HOHQMesh curve types. +# +# Keywords: outer boundary, inner boundary, parametric equations, +# circle arcs, cubic spline, curve removal +using HOHQMesh + +# Instantiate the project +sandbox_project = newProject("sandbox", "out") + +# Add the background grid +addBackgroundGrid!(sandbox_project, [1.0, 1.0, 0.0]) + +# Create and add the original outer boundary curves +outer_line1 = newEndPointsLineCurve("Line1", [0.0, -7.0, 0.0], [5.0, 3.0, 0.0]) +outer_line2 = newEndPointsLineCurve("Line2", [-5.0, 3.0, 0.0], [0.0, -7.0, 0.0]) +outer_arc = newCircularArcCurve("Arc", [0.0, 3.0, 0.0], 5.0, 0.0, 180.0, "degrees") + +addCurveToOuterBoundary!(sandbox_project, outer_line1) +addCurveToOuterBoundary!(sandbox_project, outer_arc) +addCurveToOuterBoundary!(sandbox_project, outer_line2) + +# Modify the outer boundary to have a spline instead of a straight line +removeOuterBoundaryCurveWithName!(sandbox_project, "Line2") + +spline_data = [ [0.0 -5.0 3.0 0.0] + [0.25 -2.0 1.0 0.0] + [0.5 -4.0 0.5 0.0] + [0.75 -2.0 -3.0 0.0] + [1.0 0.0 -7.0 0.0] ] +outer_spline = newSplineCurve("Spline", 5, spline_data) +addCurveToOuterBoundary!(sandbox_project, outer_spline) + +# Create and add the inner boundary curves +inner_line1 = newEndPointsLineCurve("Line1", [1.0, 5.0, 0.0], [1.0, 3.0, 0.0]) +inner_line2 = newEndPointsLineCurve("Line2", [-1.0, 3.0, 0.0], [-1.0, 5.0, 0.0]) +inner_bottom_arc = newCircularArcCurve("BottomArc", [0.0, 3.0, 0.0], 1.0, 0.0, -pi, "radians") +inner_top_arc = newCircularArcCurve("TopArc", [0.0, 5.0, 0.0], 1.0, 180.0, 0.0, "degrees") + +addCurveToInnerBoundary!(sandbox_project, inner_line1, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_bottom_arc, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_line2, "inner") +addCurveToInnerBoundary!(sandbox_project, inner_top_arc, "inner") + +# Generate a mesh +generate_mesh(sandbox_project) + +# Delete the existing mesh before modifying the inner boundary curve chain +remove_mesh!(sandbox_project) + +# Modify the inner boundary curve with an oscillatory line and a new circle arc +removeInnerBoundaryCurve!(sandbox_project, "Line1", "inner") +removeInnerBoundaryCurve!(sandbox_project, "BottomArc", "inner") + +xEqn = "x(t) = t + 1" +yEqn = "y(t) = -2 * t + 5 - 1.5 * cos(pi * t) * sin(pi * t)" +zEqn = "z(t) = 0.0" +inner_eqn = newParametricEquationCurve("wiggleLine", xEqn, yEqn, zEqn) + +new_bottom_arc = newCircularArcCurve("wideBottomArc", [0.5, 3.0, 0.0], 1.5, 0.0, -pi, "radians") + +addCurveToInnerBoundary!(sandbox_project, inner_eqn, "inner") +addCurveToInnerBoundary!(sandbox_project, new_bottom_arc, "inner") + +# Regenerate the final mesh +generate_mesh(sandbox_project) +``` \ No newline at end of file diff --git a/docs/src/tutorials/curved_outer_boundary.md b/docs/src/tutorials/curved_outer_boundary.md new file mode 100644 index 00000000..dfbaf3d2 --- /dev/null +++ b/docs/src/tutorials/curved_outer_boundary.md @@ -0,0 +1,240 @@ +# Curved outer boundary + +The purpose of this tutorial is to demonstrate how to create an unstructured mesh on +a domain with a curved outer boundary. This outer boundary curve is defined by +parametric equations and contains fine features as well as smooth regions. + +The outer boundary, background grid and mesh +are visualized for quality inspection. The tutorial also shows how to adjust the +background and add a local refinement region in order to better resolve a portion +of the curved boundary. + +### Synopsis + +This tutorial demonstrates how to: +* Define a curved outer boundary using parametric equations. +* Add and adjust the background grid. +* Visualize an interactive mesh project. +* Add manual refinement to a local region of the domain. + +## Initialization + +From a Julia REPL we load the HOHQMesh package as well as +[GLMakie](https://github.com/JuliaPlots/GLMakie.jl/), a backend of +[Makie.jl](https://github.com/JuliaPlots/Makie.jl/), to visualize the +boundary curve, mesh, etc. from the interactive tool. +```julia +julia> using GLMakie, HOHQMesh +``` +Now we are ready to interactively generate unstructured quadrilateral meshes! + +We create a new project with the name `"TheBlob"` and +assign `"out"` to be the folder where any output files from the mesh generation process +will be saved. By default, the output files created by HOHQMesh will carry the same name +as the project. For example, the resulting mesh file from this tutorial will be named +`TheBlob.mesh`. +If the folder `out` does not exist, it will be created automatically in +the current file path. +```julia +blob_project = newProject("TheBlob", "out") +``` + +## Add the outer boundary + +The outer boundary curve for the domain of interest in this tutorial is given by the +parametric equations +```math + \begin{aligned} + x(t) &= 4\cos(2 \pi t) - \frac{3}{5}\cos^3(8 \pi t),\\[0.2cm] + y(t) &= 4\sin(2 \pi t) - \frac{1}{2}\sin^2(11 \pi t),\\[0.2cm] + z(t) &= 0 + \end{aligned} + \qquad + t\in[0,1] +``` +Parametric equations in HOHQMesh can be any legitimate equation and use intrinsic functions +available in Fortran, e.g., $\sin$, $\cos$, exp. +The constant `pi` is available for use. Exponentiation is done with `^`. +All number literals are interpreted as floating point numbers. + +The following commands create a new curve for the parametric equations above +```julia +xEqn = "x(t) = 4 * cos(2 * pi * t) - 0.6 * cos(8 * pi * t)^3" +yEqn = "y(t) = 4 * sin(2 * pi * t) - 0.5 * sin(11* pi * t)^2" +zEqn = "z(t) = 0.0" +blob = newParametricEquationCurve("Blob", xEqn, yEqn, zEqn) +``` +The name of this curve is assigned to be `"Blob"`. This name is also the label that HOHQMesh +will give to this boundary curve in the resulting mesh file. + +Now that we have created the boundary curve it must be added as an outer boundary +in the `blob_project`. +```julia +addCurveToOuterBoundary!(blob_project, blob) +``` + +## Add a background grid + +HOHQMesh requires a background grid for the mesh generation process. This background grid sets +the base resolution of the desired mesh. HOHQMesh will automatically subdivide from this background +grid near sharp features of any curved boundaries. + +For a domain bounded by an outer boundary curve, this background grid is set by indicating the desired +element size in the $x$ and $y$ directions. To start, we set the background grid for `blob_project` to +have elements with side length two in each direction +```julia +addBackgroundGrid!(blob_project, [2.0, 2.0, 0.0]) +``` + +We next visualize the outer boundary curve and background grid with the following +```julia +plotProject!(blob_project, MODEL+GRID) +``` +Here, we take the sum of the keywords `MODEL` and `GRID` in order to simultaneously visualize +the curves and background grid. The resulting plot is given below. The chain of outer boundary +curves is called `"Outer"` and it contains a single curve `"Blob"` labeled in the figure by `O.1`. + +![coarse_grid](https://user-images.githubusercontent.com/25242486/174747035-f21bb8d1-386f-4036-b2e8-59e264c071d1.png) + +From the visualization we see that the background grid is likely too coarse to produce a "good" +quadrilateral mesh for this domain. We reset the background grid size to have elements with +size one half in each direction +```julia +setBackgroundGridSize!(blob_project, 0.5, 0.5) +``` +Note, that after we execute the command above the visualization updates automatically with the +outer boundary curve and the new background grid. + +![fine_grid](https://user-images.githubusercontent.com/25242486/174747046-f1bc9734-ef4e-4e4c-9055-c54ebe1537e7.png) + +The new background grid that gives a finer initial resolution looks suitable to continue +to the mesh generation. + +## Initial mesh and user adjustments + +We next generate the mesh from the information contained in the `blob_project`. +This will output the following files to the `out` folder: + +* `TheBlob.control`: A HOHQMesh control file for the current project. +* `TheBlob.tec`: A TecPlot formatted file to visualize the mesh with other software, e.g., [ParaView](https://www.paraview.org/). +* `TheBlob.mesh`: A mesh file with format `ISM-V2` (the default format). + +To do this we execute the command +```julia +generate_mesh(blob_project) + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 0.10612399999999998 + Number of nodes = 481 + Number of Edges = 895 + Number of Elements = 417 + Number of Subdivisions = 5 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.00025346 0.36181966 0.11936327 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.00002883 2.58066393 1.26340310 1.00000000 999.99900000 1.00000000 + Condition 1.00000000 3.11480166 1.18583253 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.00006177 4.80707901 1.51313656 1.00000000 4.00000000 1.00000000 + Jacobian 0.00011326 0.28172540 0.10292251 0.00000000 999.99900000 1.00000000 + Minimum Angle 29.30873612 89.99827738 73.08079323 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.00132792 156.87642432 109.37004979 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +The call to `generate_mesh` also prints mesh quality statistics to the screen and updates the +visualization. The background grid is *removed* from the visualization when the mesh is generated. + +!!! note "Mesh visualization" + Currently, only the "skeleton" of the mesh is visualized. Thus, the high-order curved boundary information + is not seen in the plot but this information **is present** in the generated mesh file. + +![initial_blob](https://user-images.githubusercontent.com/25242486/174747052-d0776ca6-5451-4d9f-accb-8d97b2db1c26.png) + +Inspecting the mesh we see that the automatic subdivision in HOHQMesh does well to capture the fine features +of the curved outer boundary. Although, we see that the mesh near the point $(-4, 0)$ is still quite coarse. +To remedy this we manually add a `RefinementCenter` near this region of the domain to force HOHQMesh to increase +the resolution in this area. We create and add this refinement region to the current project with +```julia +center = newRefinementCenter("region", "smooth", [-4.0, -0.5, 0.0], 0.4, 1.0) +addRefinementRegion!(blob_project, center) +``` +Above we create a circular refinement region centered at the point $(-4, -0.5)$ with a desired resolution size +$0.4$ and a radius of $1.0$. Upon adding this refinement region to `blob_project`, the visualization will +update to indicate the location and size of the manual refinement region. + +![refinement_blob](https://user-images.githubusercontent.com/25242486/174747059-1f58ae14-aeec-48d5-afb3-6a0614a8e29d.png) + +## Final mesh + +With the refinement region added to the project we can regenerate the mesh. Note, this will create +and save new output files `TheBlob.control`, `TheBlob.tec`, `TheBlob.mesh` and update the figure. +```julia +generate_mesh(blob_project) + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 0.11373499999999999 + Number of nodes = 505 + Number of Edges = 940 + Number of Elements = 438 + Number of Subdivisions = 5 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.00025346 0.36181966 0.11412658 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.00002884 2.47585614 1.26424390 1.00000000 999.99900000 1.00000000 + Condition 1.00000000 3.11480166 1.18425870 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.00006177 4.80707901 1.51413601 1.00000000 4.00000000 1.00000000 + Jacobian 0.00011326 0.28172540 0.09814547 0.00000000 999.99900000 1.00000000 + Minimum Angle 29.30873612 89.99827901 72.79596483 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.00132782 156.87642433 109.63912468 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +Note, the circular region indicating the refinement center is removed from the plot when the mesh is generated. + +![final_blob](https://user-images.githubusercontent.com/25242486/174747066-a804bf1d-508a-480d-bde3-47687b402604.png) + +Now we decide that we are satisfied with the mesh quality and resolution of the outer boundary curve. + +## Summary + +In this tutorial we demonstrated how to: +* Define a curved outer boundary using parametric equations. +* Add and adjust the background grid. +* Visualize an interactive mesh project. +* Add manual refinement to a local region of the domain. + +For completeness, we include a script with all the commands to generate the mesh displayed in the final image. +Note, we **do not** include the plotting in this script. +```julia +# Interactive mesh with a curved outer boundary +# +# Create an outer boundary from a set of parametric equations. +# Add manual refinement in a small region around the point (-4, -0.5). +# +# Keywords: outer boundary, parametric equations, refinement center +using HOHQMesh + +# Instantiate the project +blob_project = newProject("TheBlob", "out") + +# Create and add the outer boundary curve +xEqn = "x(t) = 4 * cos(2 * pi * t) - 0.6 * cos(8 * pi * t)^3" +yEqn = "y(t) = 4 * sin(2 * pi * t) - 0.5 * sin(11* pi * t)^2" +zEqn = "z(t) = 0.0" +blob = newParametricEquationCurve("Blob", xEqn, yEqn, zEqn) +addCurveToOuterBoundary!(blob_project, blob) + +# Add the background grid +addBackgroundGrid!(blob_project, [0.5, 0.5, 0.0]) + +# Create and add the refinement region +center = newRefinementCenter("region", "smooth", [-4.0, -0.5, 0.0], 0.4, 1.0) +addRefinementRegion!(blob_project, center) + +# Generate the mesh +generate_mesh(blob_project) +``` \ No newline at end of file diff --git a/docs/src/tutorials/introduction.md b/docs/src/tutorials/introduction.md new file mode 100644 index 00000000..fddd42b6 --- /dev/null +++ b/docs/src/tutorials/introduction.md @@ -0,0 +1,80 @@ +# [Tutorials for HOHQMesh.jl](@id Tutorials) + +The tutorial section for [HOHQMesh.jl](https://github.com/trixi-framework/HOHQMesh.jl) +provides step-by-step commands and accompanying explanations for the major features of the +[interactive mesh generation tools](@ref InteractiveTool). + +For a general overview of the capabilities and features of HOHQMesh to generate quadrilateral +and hexahedral meshes we refer to the +[Pre-made Examples](https://trixi-framework.github.io/HOHQMesh/examples/) of the HOHQMesh +documentation. + +For more information on how an unstructured mesh generated with HOHQMesh.jl can be used in +the simulation framework [Trixi.jl](https://github.com/trixi-framework/Trixi.jl) see the +[relevant tutorial](https://trixi-framework.github.io/Trixi.jl/stable/tutorials/hohqmesh_tutorial/). + +## [Straight-sided outer boundary](@ref) + +This tutorial gives an introduction to the main functionality of the interactive meshing. In +particular, adding a straight-sided bounding box for the outer domain and two circular inner boundary +chains. It also demonstrates how to adjust some of the mesh parameters as well as the output mesh file +format. + +### Synopsis + +Demonstrates how to: +* Query and adjust the `RunParameters` of a project. +* Define a rectangular outer boundary and set the background grid. +* Visualize an interactive mesh project. +* Add circular inner boundary curves. + +## [Curved outer boundary](@ref) + +This tutorial constructs an outer domain boundary using parametric equations. The background grid is then +set and a preliminary mesh is generated. It highlights how a user can manually add a refinement region where +necessary from this visual inspection. + +### Synopsis + +Demonstrates how to: +* Define a curved outer boundary using parametric equations. +* Add and adjust the background grid. +* Visualize an interactive mesh project. +* Add manual refinement to a local region of the domain. + +## [Spline curves](@ref) + +This tutorial constructs a circular outer domain and three inner boundary curves. Two of the inner curves +are constructed using cubic splines and the third inner boundary is a triangular shape built from +three straight line "curves". + +### Synopsis + +Demonstrates how to: +* Create a circular outer boundary curve. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Construct and add parametric spline curves. +* Construct and add an inner boundary chain of straight line segments. + +## [Creating and editing curves](@ref) + +This tutorial demonstrates how to construct and edit curve segments defined in inner / outer boundary +chains. A curve "chain" in the HOHQMesh context means a closed curve that is +composed of an arbitrary number of pieces. +Each curve segment of a chain can be a different curve type, e.g., a circular +arc can connect to a spline that connects to a parametric equation curve. +There are details for the removal and replacement of a portion of a chain. + +### Synopsis + +Demonstrates how to: +* Create and edit an outer boundary chain. +* Create and edit an inner boundary chain. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Discuss undo / redo capabilities. +* Construct and add parametric spline curves. +* Construct and add a curve from parametric equations. +* Construct and add straight line segments. +* Construct and add circular arc segments. \ No newline at end of file diff --git a/docs/src/tutorials/spline_curves.md b/docs/src/tutorials/spline_curves.md new file mode 100644 index 00000000..7f68b941 --- /dev/null +++ b/docs/src/tutorials/spline_curves.md @@ -0,0 +1,254 @@ +# Spline curves + +The purpose of this tutorial is to demonstrate how to create an unstructured mesh on +a domain with a curved outer boundary and three inner boundaries. +Two of the inner curves are built from cubic splines. The third inner curve is a +triangular shape built from a chain of three straight line "curves". +The outer boundary, inner boundaries, background grid and mesh +will be visualized for quality inspection. + +It provides details and clarification for the script `interactive_spline_curves.jl` +from the [examples](https://github.com/trixi-framework/HOHQMesh.jl/tree/main/examples) folder. + +### Synopsis + +This tutorial demonstrates how to: +* Create a circular outer boundary curve. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Construct and add parametric spline curves. +* Construct and add an inner boundary chain of straight line segments. + +## Initialization + +From a Julia REPL we load the HOHQMesh package as well as +[GLMakie](https://github.com/JuliaPlots/GLMakie.jl/), a backend of +[Makie.jl](https://github.com/JuliaPlots/Makie.jl/), to visualize the +curves, mesh, etc. from the interactive tool. +```julia +julia> using GLMakie, HOHQMesh +``` +Now we are ready to interactively generate unstructured quadrilateral meshes! + +We create a new project with the name `"spline_curves"` and +assign `"out"` to be the folder where any output files from the mesh generation process +will be saved. By default, the output files created by HOHQMesh will carry the same name +as the project. For example, the resulting HOHQMesh control file from this tutorial +will be named `spline_curves.control`. +If the folder `out` does not exist, it will be created automatically in +the current file path. +```julia +spline_project = newProject("spline_curves", "out") +``` + +## Add the outer boundary + +The outer boundary curve for this tutorial is a circle of radius $r=4$ centered at +the point $(0, -1)$. +We define this circular curve with the function `newCircularArcCurve` as follows +```julia +circ = newCircularArcCurve("outerCircle", # curve name + [0.0, -1.0, 0.0], # circle center + 4.0, # circle radius + 0.0, # start angle + 360.0, # end angle + "degrees") # angle units +``` +We use `"degrees"` to set the angle bounds, but `"radians"` can also be used. +The name of the curve stored in the dictionary `circ` is assigned to be `"outerCircle"`. +This curve name is also the label that HOHQMesh will give to this boundary curve in the +resulting mesh file. + +The new `circ` curve is then added to the `spline_project` as an outer boundary curve with +```julia +addCurveToOuterBoundary!(spline_project, circ) +``` + +## Add a background grid + +HOHQMesh requires a background grid for the mesh generation process. This background grid sets +the base resolution of the desired mesh. HOHQMesh will automatically subdivide from this background +grid near sharp features of any curved boundaries. + +For a domain bounded by an outer boundary curve, this background grid is set by indicating the desired +element size in the $x$ and $y$ directions. To start, we set the background grid for `spline_project` +to have elements with side length $0.6$ in each direction +```julia +addBackgroundGrid!(spline_project, [0.6, 0.6, 0.0]) +``` + +We next visualize the outer boundary curve and background grid with the following +```julia +plotProject!(spline_project, MODEL+GRID) +``` +Here, we take the sum of the keywords `MODEL` and `GRID` in order to simultaneously visualize +the outer boundary and background grid. The resulting plot is given below. The chain of outer boundary +curves is called `"Outer"` and it contains a single curve `"outerCircle"` labeled in the figure by `O.1`. + +![background_grid](https://user-images.githubusercontent.com/25242486/174798948-3a00c5b5-d910-45df-9a9a-088eb3fa360a.png) + +## Add the inner boundaries + +The domain of this tutorial will contain three inner boundary curves: +1. Cubic spline curve created from data points read in from a file. +2. Cubic spline curve created from points directly given in the code. +3. Triangular shape built from three straight line "curves". + +### Cubic spline with data from a file + +A parametric cubic spline curve can be constructed from a file of data points. The first line +of this plain text file must indicate the number of nodes. Then line-by-line the file contains +the knots $t_j$, $x_j$, $y_j$, $z_j$ where $j$ indexes the number of nodes. +If the spline curve is to be closed. The last data point must be the same as the first. +For examples, see the +[HOHQMesh documentation](https://trixi-framework.github.io/HOHQMesh/the-model/#the-spline-curve-definition) +or open the file `test_spline_curve_data.txt` in the +[examples](https://github.com/trixi-framework/HOHQMesh.jl/tree/main/examples) folder + +We create a parametric spline curve from a file with +```julia +spline1 = newSplineCurve("big_spline", joinpath(@__DIR__, "examples", "test_spline_curve_data.txt")) +``` +The name of the curve stored in the dictionary `spline1` is assigned to be `"big_spline"`. +This curve name is also the label that HOHQMesh will give to this boundary curve in the +resulting mesh file. + +The new `spline1` curve is then added to the `spline_project` as an inner boundary curve with +```julia +addCurveToInnerBoundary!(spline_project, spline1, "inner1") +``` +This inner boundary chain name `"inner1"` is used internally by HOHQMesh. The visualization +of the background grid automatically detects that a curve has been added to the project +and the plot is updated appropriately, as shown below. The chain for the inner boundary +curve is called `inner1` and it contains a single curve `"big_spline"` labeled in the figure by `1.1`. + +![one_curve](https://user-images.githubusercontent.com/25242486/174798958-5e4a57b3-ece0-4d11-a004-b39909fccbad.png) + +### Cubic spline from data in Julia + +Alternatively, a parametric cubic spline curve can be constructed directly from data points +provided in the code. These points take the form `[t, x, y, z]` where `t` is the parameter variable +that varies between $0$ and $1$. For the spline construction, the number of points is included as an +input argument as well as the actual parametric point data. +Again, if the spline curve is to be closed, the first and last data point **must** match. + +Below, we construct another parametric spline using this strategy that consists of five data points +```julia +spline_data = [ [0.0 1.75 -1.0 0.0] + [0.25 2.1 -0.5 0.0] + [0.5 2.7 -1.0 0.0] + [0.75 0.6 -2.0 0.0] + [1.0 1.75 -1.0 0.0] ] + +spline2 = newSplineCurve("small_spline", 5, spline_data) +``` +The name of the curve stored in the dictionary `spline2` is assigned to be `"small_spline"`. +This curve name is also the label that HOHQMesh will give to this boundary curve in the +resulting mesh file. + +The new `spline2` curve is then added to the `spline_project` as an inner boundary curve with +```julia +addCurveToInnerBoundary!(spline_project, spline2, "inner2") +``` +This inner boundary chain name `"inner2"` is used internally by HOHQMesh. The visualization +of the background grid automatically detects that a curve has been added to the project +and the plot is updated appropriately, as shown below. The chain for the inner boundary +curve is called `inner2` and it contains a single curve `"small_spline"` labeled in the figure by `2.1`. + +![two_curves](https://user-images.githubusercontent.com/25242486/174798962-99e0673d-e0f9-444a-a71d-7dfd9412306e.png) + +### Triangular shape + +Finally, we build a triangular shaped inner boundary curve built from a chain of three +straight lines. Each line segment is defined using the function `newEndPointsLineCurve`. +We construct the three line segments that define the edges of a triangular shape with +```julia +edge1 = newEndPointsLineCurve("triangle", # curve name + [-2.3, -1.0, 0.0], # start point + [-1.7, -1.0, 0.0]) # end point + +edge2 = newEndPointsLineCurve("triangle", # curve name + [-1.7, -1.0, 0.0], # start point + [-2.0, -0.4, 0.0]) # end point + +edge3 = newEndPointsLineCurve("triangle", # curve name + [-2.0, -0.4, 0.0], # start point + [-2.3, -1.0, 0.0]) # end point +``` +Here, each edge of the curve is given the same name `"triangle"` as this curve name +is also the label that HOHQMesh will give to this boundary curve in the +resulting mesh file. + +The three line segments `edge1`, `edge2`, and `edge3` are connected in a +counter-clockwise orientation as required by HOHQMesh. +```julia +addCurveToInnerBoundary!(spline_project, edge1, "inner3") +addCurveToInnerBoundary!(spline_project, edge2, "inner3") +addCurveToInnerBoundary!(spline_project, edge3, "inner3") +``` +The inner boundary chain name `"inner3"` is used internally for HOHQMesh. Again, +the active visualization automatically detects that new curves have been added to the project +and the plot is updated appropriately, as shown below. The chain for the inner triangular boundary +is called `inner3` and it contains a three curve segments all called `"triangle"` labeled in the figure +by `3.1`, `3.2`, and `3.3`. + +![three_curves](https://user-images.githubusercontent.com/25242486/174798968-d41d7d8e-db1e-466f-a4fa-c36f14dfae98.png) + +## Generate the mesh + +With the background grid, outer boundary curve, and all inner boundary curves added to the `spline_project` we are ready to generate the mesh. +This will output the following files to the `out` folder: + +* `spline_curves.control`: A HOHQMesh control file for the current project. +* `spline_curves.tec`: A TecPlot formatted file to visualize the mesh with other software, e.g., [ParaView](https://www.paraview.org/). +* `spline_curves.mesh`: A mesh file with format `ISM-V2` (the default format). + +To do this we execute the command +```julia +generate_mesh(spline_project) + 1 chevron elements removed from mesh. + 1 chevron elements removed from mesh. + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 0.29613000000000000 + Number of nodes = 1177 + Number of Edges = 2225 + Number of Elements = 1047 + Number of Subdivisions = 4 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.00006214 0.15607014 0.04505181 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.00008989 2.78073390 1.23192911 1.00000000 999.99900000 1.00000000 + Condition 1.00000055 3.81350981 1.15526066 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.00014319 6.76310951 1.46264239 1.00000000 4.00000000 1.00000000 + Jacobian 0.00001495 0.10424741 0.03955903 0.00000000 999.99900000 1.00000000 + Minimum Angle 37.25504203 89.96195708 74.41060580 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.03105286 157.27881545 107.90994073 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +The call to `generate_mesh` also prints mesh quality statistics to the screen. +HOHQMesh also reports mesh clean-up that occurred during the generation process, in this case the removal of +"bad" chevron shaped elements that were present within the automatic subdivision procedure. +The visualization updates automatically and the background grid is *removed* after when the mesh is generated. + +!!! note "Mesh visualization" + Currently, only the "skeleton" of the mesh is visualized. Thus, the high-order curved boundary information + is not seen in the plot but this information **is present** in the generated mesh file. + +![final_spline](https://user-images.githubusercontent.com/25242486/174798986-6b900fa8-840c-4c04-bc61-00f0749af1be.png) + +Inspecting the mesh we see that the automatic subdivision in HOHQMesh does well to capture the fine features +of the curved inner boundaries, particularly near the sharp angles of the `"big_spline"` curve. We decide that we +are satisfied with the overall mesh quality. + +## Summary + +In this tutorial we demonstrated how to: +* Create a circular outer boundary curve. +* Add the background grid when an outer boundary curve is present. +* Visualize an interactive mesh project. +* Construct and add parametric spline curves. +* Construct and add an inner boundary chain of straight line segments. \ No newline at end of file diff --git a/docs/src/tutorials/straight_outer_boundary.md b/docs/src/tutorials/straight_outer_boundary.md new file mode 100644 index 00000000..7ec39262 --- /dev/null +++ b/docs/src/tutorials/straight_outer_boundary.md @@ -0,0 +1,206 @@ +# Straight-sided outer boundary + +The purpose of this tutorial is to demonstrate how to create an unstructured mesh on +a rectangular domain that contains two circular inner boundaries. Further, we show how +to adjust some of the default mesh parameters as well as the +output mesh file format. The outer boundary, background grid and mesh +will be visualized for quality inspection. + +It provides details and clarification for the script `interactive_outer_box_two_circles.jl` +from the [examples](https://github.com/trixi-framework/HOHQMesh.jl/tree/main/examples) folder. + +### Synopsis + +This tutorial demonstrates how to: +* Query and adjust the `RunParameters` of a project. +* Define a rectangular outer boundary and set the background grid. +* Visualize an interactive mesh project. +* Add circular inner boundary curves. + +## Initialization + +From a Julia REPL we load the HOHQMesh package as well as +[GLMakie](https://github.com/JuliaPlots/GLMakie.jl/), a backend of +[Makie.jl](https://github.com/JuliaPlots/Makie.jl/), to visualize the +curves, mesh, etc. from the interactive tool. +```julia +julia> using GLMakie, HOHQMesh +``` +Now we are ready to interactively generate unstructured quadrilateral meshes! + +We create a new project with the name `"box_two_circles"` and +assign `"out"` to be the folder where any output files from the mesh generation process +will be saved. By default, the output files created by HOHQMesh will carry the same name +as the project. For example, the resulting HOHQMesh control file from this tutorial +will be named `box_two_circles.control`. +If the folder `out` does not exist, it will be created automatically in +the current file path. +```julia +box_project = newProject("box_two_circles", "out") +``` + +## Adjusting project parameters + +When a new project is created it is filled with several default +`RunParameters` such as the polynomial order used to represent curved boundaries +or the mesh file format. These `RunParameters` can be queried and adjusted with +appropriate getter/setter pairs, see [Controlling the mesh generation](@ref) +for more details. + +For the `box_project` we first query the current values for the polynomial +order and the mesh output format +```julia +julia> getPolynomialOrder(box_project) +5 + +julia> getMeshFileFormat(box_project) +"ISM-V2" +``` + +We change these quantities in the `box_project` with the corresponding +setter functions. For this we will set the polynomial order to be $4$ and the mesh file format +to be `ABAQUS`. See the +[P4est-based mesh](https://trixi-framework.github.io/Trixi.jl/stable/meshes/p4est_mesh/) +section of the [Trixi.jl](https://github.com/trixi-framework/Trixi.jl) documentation for a +detailed overview of this mesh file format. +```julia +setPolynomialOrder!(box_project, 4) +setMeshFileFormat!(box_project, "ABAQUS") +``` + +## Add the background grid + +HOHQMesh requires a background grid for the mesh generation process. This background grid sets +the base resolution of the desired mesh. HOHQMesh will automatically subdivide from this background +grid near any curved boundaries. + +The domain for this tutorial is a rectangular box with the bounds $[0,30]\times[0,15]$. Because no +outer boundary curve is present there are two (equivalent) strategies for us to define the bounds +of a rectangular domain and the size of the background grid: +1. Set the lower left corner point of the domain $(x_0, y_0)$, define the element size in each spatial direction + $\Delta x$ and $\Delta y$, and the number of steps taken in each direction $N_x, N_y$. The resulting background + grid will have the extent $[x_0, x_0 + N_x \Delta x]$ by $[y_0, y_0 + N_y \Delta y]$. For this example, we set + a background grid of Cartesian elements with size one in each dimension with + the following commands + ```julia + lower_left = [0.0, 0.0, 0.0] + spacing = [1.0, 1.0, 0.0] + num_intervals = [30, 15, 0] + addBackgroundGrid!(box_project, lower_left, spacing, num_intervals) + ``` +2. Set the bounding box with extent values ordered as `[top, left, bottom, right]` and provide the number + the number of steps in each direction. To set a background grid of Cartesian elements with size one in + each dimension for the rectangular box $[0,30]\times[0,15]$ we use + ```julia + bounds = [15.0, 0.0, 0.0, 30.0] + N = [30, 15, 0] + addBackgroundGrid!(box_project, bounds, N) + ``` +Next, we visualize the `box_project` to ensure that the background grid has been added correctly. +```julia +plotProject!(box_project, GRID) +``` +We use the keyword and `GRID` to indicate that we want the background grid to be included in the +visualization. + +![background](https://user-images.githubusercontent.com/25242486/174775018-86936c6b-ba69-456e-9aaf-c5054a4aacbe.png) + +## Add the inner boundaries + +Next, we add the two circular inner boundary curves with different radii. + +The first circle will have radius $r=2$ and be centered at the point $(4, 4)$. +We define this circular curve with the function `newCircularArcCurve` as follows +```julia +circle1 = newCircularArcCurve("circle1", # curve name + [4.0, 4.0, 0.0], # circle center + 2.0, # circle radius + 0.0, # start angle + 360.0, # end angle + "degrees") # angle units +``` +We use `"degrees"` to set the angle bounds, but `"radians"` can also be used. +The name of the curve stored in the dictionary `circle1` is assigned to be `"circle1"`. +This curve name is also the label that HOHQMesh will give to this boundary curve in the +resulting mesh file. + +The new `circle1` curve is then added to the `box_project` as an inner boundary curve with +```julia +addCurveToInnerBoundary!(box_project, circle1, "inner1") +``` +This inner boundary chain name `"inner1"` is used internally by HOHQMesh. The visualization +of the background grid automatically detects that a curve has been added to the project +and the plot is updated appropriately, as shown below. The chain for the inner boundary +curve is called `"inner1"` and it contains a single curve `"circle1"` labeled in the figure by `1.1`. + +![first_circle](https://user-images.githubusercontent.com/25242486/174775027-62a094f7-bbba-4c1c-a389-99562c2e5fe2.png) + +With analogous steps we create another circular curve with radius $r=4$, centered at $(20, 9)$ and +add it as a second inner curve to the `box_project`. Note, for this curve we use radians +for the angle units. +```julia +circle2 = newCircularArcCurve("circle2", # curve name + [20.0, 9.0, 0.0], # circle center + 4.0, # circle radius + 0.0, # start angle + 2.0 * pi, # end angle + "radians") # angle units +addCurveToInnerBoundary!(box_project, circle2, "inner2") +``` +Again, the `box_project` detects that a curve has been added to it +and the visualization is automatically updated with the second circular curve. +The chain for the second inner boundary curve is called `"inner2"` and it contains +a single curve `"circle2"` labeled in the figure by `2.1`. + +![second_circle](https://user-images.githubusercontent.com/25242486/174775037-a9144f93-78da-48ae-976b-7cfaeca68240.png) + +## Generate the mesh + +With the background grid and all inner boundary curves added to the `box_project` +we can generate the mesh. +This will output the following files to the `out` folder: + +* `box_two_circles.control`: A HOHQMesh control file for the current project. +* `box_two_circles.tec`: A TecPlot formatted file to visualize the mesh with other software, e.g., [ParaView](https://www.paraview.org/). +* `box_two_circles.inp`: A mesh file with format `ABAQUS` that was set above. + +To do this we execute the command +```julia +generate_mesh(box_project) + + ******************* + 2D Mesh Statistics: + ******************* + Total time = 3.5553999999999995E-002 + Number of nodes = 498 + Number of Edges = 921 + Number of Elements = 422 + Number of Subdivisions = 0 + + Mesh Quality: + Measure Minimum Maximum Average Acceptable Low Acceptable High Reference + Signed Area 0.34513058 1.15383206 0.91833833 0.00000000 999.99900000 1.00000000 + Aspect Ratio 1.00000004 1.71083844 1.08733476 1.00000000 999.99900000 1.00000000 + Condition 1.00000000 1.46558793 1.04922640 1.00000000 4.00000000 1.00000000 + Edge Ratio 1.00000006 2.43503343 1.16700825 1.00000000 4.00000000 1.00000000 + Jacobian 0.17863168 1.07210721 0.86801359 0.00000000 999.99900000 1.00000000 + Minimum Angle 50.56155029 89.99999787 83.84466557 40.00000000 90.00000000 90.00000000 + Maximum Angle 90.00000259 136.97479459 96.69930735 90.00000000 135.00000000 90.00000000 + Area Sign 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 1.00000000 +``` +The call to `generate_mesh` also prints mesh quality statistics to the screen and updates the +visualization. The background grid is *removed* from the visualization when the mesh is generated and the resulting +mesh is visualized instead. + +![final_circle](https://user-images.githubusercontent.com/25242486/174775040-e4a04503-83f3-4f80-b087-972bd8dbb5e9.png) + +From a visual inspection we decide that we are satisfied with the mesh quality and resolution near +the inner circular boundaries. + +## Summary + +In this tutorial we demonstrated how to: +* Query and adjust the `RunParameters` of a project. +* Define a rectangular outer boundary and set the background grid. +* Visualize an interactive mesh project. +* Add circular inner boundary curves. diff --git a/examples/interactive_from_control_file.jl b/examples/interactive_from_control_file.jl index 768232fc..c20718cc 100644 --- a/examples/interactive_from_control_file.jl +++ b/examples/interactive_from_control_file.jl @@ -35,5 +35,5 @@ if isdefined(Main, :Makie) generate_mesh(p) -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, # the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/interactive_outer_boundary.jl b/examples/interactive_outer_boundary.jl index abb183b8..8b732f28 100644 --- a/examples/interactive_outer_boundary.jl +++ b/examples/interactive_outer_boundary.jl @@ -65,5 +65,5 @@ if isdefined(Main, :Makie) generate_mesh(p) -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, # the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/interactive_outer_boundary_generic.jl b/examples/interactive_outer_boundary_generic.jl index 73e9cb11..ef55a8e0 100644 --- a/examples/interactive_outer_boundary_generic.jl +++ b/examples/interactive_outer_boundary_generic.jl @@ -63,5 +63,5 @@ if isdefined(Main, :Makie) generate_mesh(p) -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, # the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/interactive_outer_box_two_circles.jl b/examples/interactive_outer_box_two_circles.jl index dcb47762..589226e6 100644 --- a/examples/interactive_outer_box_two_circles.jl +++ b/examples/interactive_outer_box_two_circles.jl @@ -14,7 +14,8 @@ p = newProject("box_two_circles", "out") # Adjust some `RunParameters` and overwrite the defaults values. In this case, we # set a new value for the boundary order polynomial representation and adjust the -# output mesh file format to be `ABAQUS`, which will produce a mesh file `outer_box.inp` +# output mesh file format to be `ABAQUS`, which will produce a mesh file +# `box_two_circles.inp` setPolynomialOrder!(p, 4) setMeshFileFormat!(p, "ABAQUS") @@ -27,7 +28,7 @@ lower_left = [0.0, 0.0, 0.0] spacing = [1.0, 1.0, 0.0] num_intervals = [30, 15, 0] -# These three quanties can set the background grid that is required by HOHQMesh for a given domain. +# These three quantities set the background grid that is required by HOHQMesh for a given domain. addBackgroundGrid!(p, lower_left, spacing, num_intervals) @@ -69,5 +70,5 @@ end generate_mesh(p) -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, # the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/interactive_spline_curves.jl b/examples/interactive_spline_curves.jl index bdd57af3..eabe2886 100644 --- a/examples/interactive_spline_curves.jl +++ b/examples/interactive_spline_curves.jl @@ -26,19 +26,18 @@ circ = newCircularArcCurve("outerCircle", [0.0, -1.0, 0.0], 4.0, 0.0, 360.0, "de addCurveToOuterBoundary!(p, circ) # Inner boundaries will have three curves: -# (i) Cubic spline curve created from data pooints read in from a file. +# (i) Cubic spline curve created from data points read in from a file. # (ii) Cubic spline curve created from points directly given in the code. -# (iii) Triangle shape built from three staight line "curves". +# (iii) Triangle shape built from three straight line "curves". # Create the three interior curves. The curve name are those that are output as the # given boundary names in the mesh file. -# First inner boundary is a parametric cubic spline read in from a file. Note, for convenience, -# we reuse a spline from the testing routines. For information on formatting cubic spline data -# files see the HOHQMesh documentation: +# First inner boundary is a parametric cubic spline read in from a file. For information +# on formatting cubic spline data files see the HOHQMesh documentation: # https://trixi-framework.github.io/HOHQMesh/the-model/#the-spline-curve-definition -spline1 = newSplineCurve("big_spline", joinpath(@__DIR__, "..", "test", "test_spline_curve_data.txt")) +spline1 = newSplineCurve("big_spline", joinpath(@__DIR__, "test_spline_curve_data.txt")) addCurveToInnerBoundary!(p, spline1, "inner1") # Second inner boundary is a parametric cubic spline with data points directly provided @@ -84,5 +83,5 @@ if isdefined(Main, :Makie) generate_mesh(p) -# After the mesh sucessfully generates mesh statistics, such as the number of corner nodes, +# After the mesh successfully generates mesh statistics, such as the number of corner nodes, # the number of elements etc., are printed to the REPL. \ No newline at end of file diff --git a/examples/test_spline_curve_data.txt b/examples/test_spline_curve_data.txt new file mode 100644 index 00000000..2e576e1d --- /dev/null +++ b/examples/test_spline_curve_data.txt @@ -0,0 +1,78 @@ +77 +0.000000000000000 -1.000000000000000 -1.000000000000000 0.000000000000000 +0.013157894736842 -0.995929487847041 -0.984513308895507 0.000000000000000 +0.026315789473684 -0.984006935621602 -0.940263574448587 0.000000000000000 +0.039473684210526 -0.964665819673838 -0.870566304959074 0.000000000000000 +0.052631578947368 -0.938339616353904 -0.778737008726803 0.000000000000000 +0.065789473684211 -0.905461802011955 -0.668091194051611 0.000000000000000 +0.078947368421053 -0.866465852998146 -0.541944369233333 0.000000000000000 +0.092105263157895 -0.821785245662633 -0.403612042571803 0.000000000000000 +0.105263157894737 -0.771853456355570 -0.256409722366859 0.000000000000000 +0.118421052631579 -0.717103961427114 -0.103652916918335 0.000000000000000 +0.131578947368421 -0.657970237227418 0.051342865473934 0.000000000000000 +0.144736842105263 -0.594885760106638 0.205262116510112 0.000000000000000 +0.157894736842105 -0.528284006414929 0.354789327890363 0.000000000000000 +0.171052631578947 -0.458598452502447 0.496608991314852 0.000000000000000 +0.184210526315789 -0.386262574719347 0.627405598483744 0.000000000000000 +0.197368421052632 -0.311709849415783 0.743863641097203 0.000000000000000 +0.210526315789474 -0.235373752941912 0.842667610855393 0.000000000000000 +0.223684210526316 -0.157687761647887 0.920501999458480 0.000000000000000 +0.236842105263158 -0.079085351883865 0.974051298606627 0.000000000000000 +0.250000000000000 0.000000000000000 1.000000000000000 0.000000000000000 +0.263157894736842 0.079132214191990 0.996076583425322 0.000000000000000 +0.276315789473684 0.157864797034136 0.964185481015558 0.000000000000000 +0.289473684210526 0.235748651406911 0.907275112990232 0.000000000000000 +0.302631578947368 0.312334680190782 0.828293899568867 0.000000000000000 +0.315789473684211 0.387173786266220 0.730190260970987 0.000000000000000 +0.328947368421053 0.459816872513694 0.615912617416116 0.000000000000000 +0.342105263157895 0.529814841813676 0.488409389123779 0.000000000000000 +0.355263157894737 0.596718597046633 0.350628996313498 0.000000000000000 +0.368421052631579 0.660079041093037 0.205519859204799 0.000000000000000 +0.381578947368421 0.719447076833358 0.056030398017204 0.000000000000000 +0.394736842105263 0.774373607148064 -0.094890967029763 0.000000000000000 +0.407894736842105 0.824409534917626 -0.244295815716577 0.000000000000000 +0.421052631578947 0.869105763022515 -0.389235727823714 0.000000000000000 +0.434210526315789 0.908013194343199 -0.526762283131652 0.000000000000000 +0.447368421052632 0.940682731760148 -0.653927061420865 0.000000000000000 +0.460526315789474 0.966665278153833 -0.767781642471830 0.000000000000000 +0.473684210526316 0.985511736404724 -0.865377606065024 0.000000000000000 +0.486842105263158 0.996773009393289 -0.943766531980922 0.000000000000000 +0.500000000000000 1.000000000000000 -1.000000000000000 0.000000000000000 +0.513157894736842 0.994898517068294 -1.032013465103201 0.000000000000000 +0.526315789473684 0.981793993293483 -1.041277883073334 0.000000000000000 +0.539473684210526 0.961166767333847 -1.030148084893675 0.000000000000000 +0.552631578947368 0.933497177847667 -1.000978901547498 0.000000000000000 +0.565789473684211 0.899265563493221 -0.956125164018079 0.000000000000000 +0.578947368421053 0.858952262928790 -0.897941703288692 0.000000000000000 +0.592105263157895 0.813037614812655 -0.828783350342616 0.000000000000000 +0.605263157894737 0.762001957803095 -0.751004936163122 0.000000000000000 +0.618421052631579 0.706325630558390 -0.666961291733489 0.000000000000000 +0.631578947368421 0.646488971736821 -0.579007248036990 0.000000000000000 +0.644736842105263 0.582972319996667 -0.489497636056901 0.000000000000000 +0.657894736842105 0.516256013996209 -0.400787286776498 0.000000000000000 +0.671052631578947 0.446820392393727 -0.315231031179056 0.000000000000000 +0.684210526315789 0.375145793847500 -0.235183700247849 0.000000000000000 +0.697368421052632 0.301712557015808 -0.163000124966155 0.000000000000000 +0.710526315789474 0.227001020556933 -0.101035136317247 0.000000000000000 +0.723684210526316 0.151491523129152 -0.051643565284402 0.000000000000000 +0.736842105263158 0.075664403390749 -0.017180242850895 0.000000000000000 +0.750000000000000 0.000000000000000 0.000000000000000 0.000000000000000 +0.763157894736842 -0.075055193385125 -0.001715681169683 0.000000000000000 +0.776315789473684 -0.149190063107908 -0.020972184616666 0.000000000000000 +0.789473684210526 -0.222127340511945 -0.055672422052361 0.000000000000000 +0.802631578947368 -0.293589756940828 -0.103719305188178 0.000000000000000 +0.815789473684211 -0.363300043738154 -0.163015745735530 0.000000000000000 +0.828947368421053 -0.430980932247516 -0.231464655405828 0.000000000000000 +0.842105263157895 -0.496355153812509 -0.306968945910482 0.000000000000000 +0.855263157894737 -0.559145439776727 -0.387431528960906 0.000000000000000 +0.868421052631579 -0.619074521483765 -0.470755316268511 0.000000000000000 +0.881578947368421 -0.675865130277217 -0.554843219544706 0.000000000000000 +0.894736842105263 -0.729239997500677 -0.637598150500906 0.000000000000000 +0.907894736842105 -0.778921854497740 -0.716923020848520 0.000000000000000 +0.921052631578947 -0.824633432612001 -0.790720742298961 0.000000000000000 +0.934210526315789 -0.866097463187054 -0.856894226563639 0.000000000000000 +0.947368421052632 -0.903036677566493 -0.913346385353967 0.000000000000000 +0.960526315789474 -0.935173807093912 -0.957980130381355 0.000000000000000 +0.973684210526316 -0.962231583112907 -0.988698373357216 0.000000000000000 +0.986842105263158 -0.983932736967071 -1.003404025992960 0.000000000000000 +1.000000000000000 -1.000000000000000 -1.000000000000000 0.000000000000000 diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 47622882..56b7d73b 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -20,9 +20,9 @@ function __init__() end # -# Include functionality for HQMTool interactive reading and writing a model for HOHQMesh +# Include interactive mesh functionality for creating, reading, and writing a model for HOHQMesh. # Note, The visualzation routines are included above in the `__init__` because -# Makie is required +# Makie is required. # # Core interactive tool routines for control file readin, curve evaluation, etc. @@ -50,10 +50,11 @@ include("Project/SmootherAPI.jl") # Main routine that uses HOHQMesh to generate a mesh from an interactive `Project` include("Mesh/Meshing.jl") -# Main wrapper to generate a mesh from a control file +# Generic main function to generate a mesh from a control file +# or an interactive mesh `Project` export generate_mesh -# Generic functions for the HQMTool interface +# Generic functions for the interactice mesh interface export new, add!, getCurve, @@ -61,17 +62,14 @@ export new, remove! # -# TODO: Go through and cleanup this exporting. +# Export the front facing interactive mesh functionality, e.g., getter/setter pairs. # + # Functions from `BackgroundGridAPI.jl` -export addBackgroundGrid!, - removeBackgroundGrid!, - setBackgroundGridSize!, - getBackgroundGridSize, +export addBackgroundGrid!, removeBackgroundGrid!, + setBackgroundGridSize!, getBackgroundGridSize, getBackgroundGridLowerLeft, - getBackgroundGridSteps, - setBackgroundGridLowerLeft!, - setBackgroundGridSteps! + getBackgroundGridSteps # Functions from `ControlInputAPI.jl` export getControlDict, @@ -83,48 +81,29 @@ export newParametricEquationCurve, newEndPointsLineCurve, newCircularArcCurve, newSplineCurve, - setCurveName!, - getCurveName, + setCurveName!, getCurveName, getCurveType, setXEqn!, getXEqn, setYEqn!, getYEqn, setZEqn!, getZEqn, - setStartPoint!, - getStartPoint, - setEndPoint!, - getEndPoint, - setArcUnits!, - getArcUnits, - setArcCenter!, - getArcCenter, - setArcStartAngle!, - getArcStartAngle, - setArcEndAngle!, - getArcEndAngle, - setArcRadius!, - getArcRadius, - setSplineNKnots!, - getSplineNKnots, - setSplinePoints!, - getSplinePoints, - curvePoint, - curvePoints, - peEquationCurvePoints, - peEquationCurvePoint + setStartPoint!, getStartPoint, + setEndPoint!, getEndPoint, + setArcUnits!, getArcUnits, + setArcCenter!, getArcCenter, + setArcStartAngle!, getArcStartAngle, + setArcEndAngle!, getArcEndAngle, + setArcRadius!, getArcRadius, + setSplineNKnots!, getSplineNKnots, + setSplinePoints!, getSplinePoints # Functions from `ModelAPI.jl` -export addCurveToOuterBoundary!, - removeOuterBoundaryCurveWithName!, +export addCurveToOuterBoundary!, removeOuterBoundaryCurveWithName!, getOuterBoundaryCurveWithName, - insertOuterBoundaryCurveAtIndex!, - removeOuterBoundaryCurveAtIndex!, - addOuterBoundary!, - removeOuterBoundary!, + insertOuterBoundaryCurveAtIndex!, removeOuterBoundaryCurveAtIndex!, + addOuterBoundary!, removeOuterBoundary!, getOuterBoundaryChainList, - addCurveToInnerBoundary!, - removeInnerBoundaryCurve!, - insertInnerBoundaryCurveAtIndex!, - removeInnerBoundaryCurveAtIndex!, + addCurveToInnerBoundary!, removeInnerBoundaryCurve!, + insertInnerBoundaryCurveAtIndex!, removeInnerBoundaryCurveAtIndex!, removeInnerBoundary!, addInnerBoundaryWithName!, getChainIndex, @@ -136,85 +115,42 @@ export addCurveToOuterBoundary!, getDictInModelDictNamed # Functions from `Project.jl` -export openProject, - saveProject, - newProject, - hasBackgroundGrid, - assemblePlotArrays, - projectBounds, - projectGrid, - curveDidChange, - modelDidChange, - backgroundGridDidChange, - refinementWasAdded, - refinementDidChange, - meshWasGenerated, - meshWasDeleted +export newProject, + openProject, + saveProject # Functions from `RefinementRegionsAPI.jl` export newRefinementCenter, - addRefinementRegion!, - addRefinementRegionPoints!, - refinementRegionPoints, - getRefinementRegionCenter, - removeRefinementRegion!, - insertRefinementRegion!, newRefinementLine, - getRefinementRegion, - getAllRefinementRegions, - getRefinementRegion, - setRefinementType!, - getRefinementType, - setRefinementName!, - getRefinementName, - setRefinementLocation!, - getRefinementLocation, - setRefinementGridSize!, - getRefinementGridSize, - setRefinementWidth!, - getRefinementWidth, - setRefinementStart!, - getRefinementStart, - setRefinementEnd!, - getRefinementEnd + addRefinementRegion!, getRefinementRegion, getAllRefinementRegions, + getRefinementRegionCenter, + insertRefinementRegion!, removeRefinementRegion!, + setRefinementType!, getRefinementType, + setRefinementName!, getRefinementName, + setRefinementLocation!, getRefinementLocation, + setRefinementGridSize!, getRefinementGridSize, + setRefinementWidth!, getRefinementWidth, + setRefinementStart!, getRefinementStart, + setRefinementEnd!, getRefinementEnd # Functions from `RunParametersAPI.jl` -export addRunParameters!, - removeRunParameters!, - setName!, - getName, - setPolynomialOrder!, - getPolynomialOrder, - setMeshFileFormat!, - getMeshFileFormat, - setPlotFileFormat!, - getPlotFileFormat, - setFileNames!, - getMeshFileName, - getPlotFileName, - getStatsFileName +export addRunParameters!, removeRunParameters!, + setName!, getName, + setPolynomialOrder!, getPolynomialOrder, + setMeshFileFormat!, getMeshFileFormat, + setPlotFileFormat!, getPlotFileFormat, + setFileNames!, getMeshFileName, getPlotFileName, getStatsFileName # Functions from `SmootherAPI.jl` -export addSpringSmoother!, - setSmoothingStatus!, - getSmoothingStatus, - setSmoothingType!, - getSmoothingType, - setSmoothingIterations!, - getSmoothingIterations, - removeSpringSmoother! +export addSpringSmoother!, removeSpringSmoother!, + setSmoothingStatus!, getSmoothingStatus, + setSmoothingType!, getSmoothingType, + setSmoothingIterations!, getSmoothingIterations # Functions from `Undo.jl` -export undo, - redo, - registerUndo, - registerWithUndoManager, - registerRedo, - clearUndoRedo, - undoActionName, - redoActionName, - disableUndo, - enableUndo +export undo, undoActionName, + redo, redoActionName, + clearUndoRedo # Functions from `Meshing.jl`, generate_mesh is already exported export remove_mesh! diff --git a/src/Mesh/Meshing.jl b/src/Mesh/Meshing.jl index 122960b9..00e1e67d 100644 --- a/src/Mesh/Meshing.jl +++ b/src/Mesh/Meshing.jl @@ -2,7 +2,8 @@ """ generate_mesh(proj::Project) -Generate a mesh based on the `proj` created using the HQMTool. First a check is made +Generate a mesh from the information stored in a `Project` created using the +interactive mesh functionality. First a check is made if a background grid exists and all inner/outer boundary curves are valid. This function will then make a HOHQMesh control file from the control dictionary `proj.controlDict` diff --git a/src/Project/BackgroundGridAPI.jl b/src/Project/BackgroundGridAPI.jl index 89b194ef..4eae8c73 100644 --- a/src/Project/BackgroundGridAPI.jl +++ b/src/Project/BackgroundGridAPI.jl @@ -141,7 +141,7 @@ end """ - function getBackgroundGridLowerLeft(proj::Project) + getBackgroundGridLowerLeft(proj::Project) Returns the [x,y] of the lower left point of the background grid. """ @@ -156,7 +156,7 @@ end """ - function getBackgroundGridSteps(proj::Project) + getBackgroundGridSteps(proj::Project) Returns the [Nx,Ny,Nz] for the background grid. """ @@ -231,7 +231,7 @@ end """ setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, key::String) -Set the grid size dx of an existing background grid withing `proj`. Here, the new grid +Set the grid size dx of an existing background grid within `proj`. Here, the new grid size in either direction is passed individually with `dx`and `dy`. """ function setBackgroundGridSize!(proj::Project, dx::Float64, dy::Float64, key::String) diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index af97df91..ea7e289b 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -17,6 +17,7 @@ function addCurveToOuterBoundary!(proj::Project, crv::Dict{String,Any}) enableUndo() registerWithUndoManager(proj,removeOuterBoundaryCurveWithName!,(crv["name"],),"Add Outer Boundary Curve") + println("Added curve ",getCurveName(crv)," to the outer boundary chain.") end @@ -171,6 +172,7 @@ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundary registerWithUndoManager(proj,removeInnerBoundaryCurve!, (crv["name"],boundaryName), "Add Inner Boundary Curve") + println("Added curve ",getCurveName(crv)," to the ",boundaryName," chain.") end """ diff --git a/src/Project/Project.jl b/src/Project/Project.jl index e6d6c69b..3ab31a16 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -30,7 +30,7 @@ mutable struct Project meshShouldUpdate ::Bool end -const defaultPlotPts = 50 +const defaultPlotPts = 200 const meshFileFormats = Set(["ISM", "ISM-V2", "ABAQUS"]) const plotFileFormats = Set(["sem", "skeleton"]) const smootherTypes = Set(["LinearSpring", "LinearAndCrossbarSpring"]) diff --git a/src/Project/Undo.jl b/src/Project/Undo.jl index e7c9d019..b5489467 100644 --- a/src/Project/Undo.jl +++ b/src/Project/Undo.jl @@ -15,7 +15,8 @@ end #= TODO: The undo framework currently works globally, within the REPL. It *should* work project-by-project. -Note that these projects refer to the `HQMTool` projects, not Julia projects in the sense of `Project.toml`. +Note that these projects refer to the interactive mesh functionality projects, +not Julia projects in the sense of `Project.toml`. To make the undo framework project based, undo() would be replaced by undo(project) and an .undoStack property of the project would replace HQMglobalUndoStack. This is not a big deal except if multiple projects are open, and muliple objects like curves have been diff --git a/test/runtests.jl b/test/runtests.jl index 424db505..18349055 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -51,7 +51,7 @@ isdir(outdir) && rm(outdir, recursive=true) end # testset "HOHQMesh.jl" -# Unit tests for the HQMTool interactive functionality +# Unit tests for the interactive mesh functionality # Background grid test routines include("test_background_grid.jl") @@ -62,13 +62,13 @@ include("test_curve.jl") # Model test routines include("test_model.jl") -# HQMTool project test routines +# Interactive mesh project test routines include("test_hqmtool_project.jl") -# HQMTool interactive examples available in examples folder +# Interactive mesh scripts available in examples folder include("test_examples.jl") -# HQMTool project + visualzation test routines +# Interactive mesh project + visualzation test routines include("test_project_with_viz.jl") # Refinement test routines diff --git a/test/test_background_grid.jl b/test/test_background_grid.jl index d262ac0b..16022821 100644 --- a/test/test_background_grid.jl +++ b/test/test_background_grid.jl @@ -28,18 +28,18 @@ using Test # # Add with method 1 (when outer boundary is present): [dx,dy,dz] # - @test hasBackgroundGrid(p) == false + @test HOHQMesh.hasBackgroundGrid(p) == false addBackgroundGrid!(p,[0.1,0.2,0.0]) - @test hasBackgroundGrid(p) == true + @test HOHQMesh.hasBackgroundGrid(p) == true bgs = getBackgroundGridSize(p) @test isapprox(bgs,[0.1,0.2,0.0]) removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false + @test HOHQMesh.hasBackgroundGrid(p) == false # # Add with method 2: lower left, dx, nPts # addBackgroundGrid!(p,[-1.0,-1.0,0.0],[0.1,0.1,0.0], [10,10,0]) - @test hasBackgroundGrid(p) == true + @test HOHQMesh.hasBackgroundGrid(p) == true @test getBackgroundGridSteps(p) == [10,10,0] @test isapprox(getBackgroundGridSize(p),[0.1,0.1,0.0]) @test isapprox(getBackgroundGridLowerLeft(p),[-1.0,-1.0,0.0]) @@ -47,16 +47,16 @@ using Test # Test undo, redo # undo() - @test hasBackgroundGrid(p) == false + @test HOHQMesh.hasBackgroundGrid(p) == false redo() - @test hasBackgroundGrid(p) == true + @test HOHQMesh.hasBackgroundGrid(p) == true removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false + @test HOHQMesh.hasBackgroundGrid(p) == false # # Add with method 3 (No outer bounday, preferred): bounding box + nPts # addBackgroundGrid!(p, [10.0,-10.0,-5.0,5.0], [10,10,0]) - @test hasBackgroundGrid(p) == true + @test HOHQMesh.hasBackgroundGrid(p) == true @test getBackgroundGridSteps(p) == [10,10,0] @test isapprox(getBackgroundGridSize(p),[1.5,1.5,0.0]) @test isapprox(getBackgroundGridLowerLeft(p),[-10.0,-5.0,0.0]) @@ -68,7 +68,7 @@ using Test @test getBackgroundGridSteps(p) == [15,15,0] removeBackgroundGrid!(p) - @test hasBackgroundGrid(p) == false + @test HOHQMesh.hasBackgroundGrid(p) == false # # There are no longer any background grid. Delete the notification center piece as well. # Note that the notification center is global and can have multiple observers. So we test diff --git a/test/test_curve.jl b/test/test_curve.jl index 10c81381..bd548f34 100644 --- a/test/test_curve.jl +++ b/test/test_curve.jl @@ -68,7 +68,7 @@ using Test @test getYEqn(crv) == yEqn @test getZEqn(crv) == zEqn - value = curvePoint(crv, 0.25) + value = HOHQMesh.curvePoint(crv, 0.25) @test value == [0.25, 0.5, 0.0] # tests to reset curve name and equation definitions @@ -99,10 +99,10 @@ using Test @test getStartPoint(crv) == xStart @test getEndPoint(crv) == xEnd - pt = curvePoint(crv, 0.5) + pt = HOHQMesh.curvePoint(crv, 0.5) @test isapprox(pt,[0.5,0.5,0.0]) - pts = curvePoints(crv, 2) + pts = HOHQMesh.curvePoints(crv, 2) @test isapprox(pts[1,:],[0.0,0.0]) @test isapprox(pts[2,:],[0.5,0.5]) @test isapprox(pts[3,:],[1.0,1.0]) @@ -139,10 +139,10 @@ using Test @test getArcStartAngle(crv) == startAngleD @test getArcUnits(crv) == "degrees" - pt = curvePoint(crv, 0.5) + pt = HOHQMesh.curvePoint(crv, 0.5) @test isapprox(pt,[0.0,2.0,0.0]) - pts = curvePoints(crv,2) + pts = HOHQMesh.curvePoints(crv,2) @test isapprox(pts[1,:],[2.0,0.0]) @test isapprox(pts[2,:],[0.0,2.0]) @test isapprox(pts[3,:],[-2.0,0.0]) @@ -192,15 +192,15 @@ using Test @test getCurveName(crv) == name @test getSplineNKnots(crv) == nKnots - pt = curvePoint(crv, 0.5) + pt = HOHQMesh.curvePoint(crv, 0.5) @test isapprox(pt, [0.5^3, 0.5^3 + 0.5^2, 0.0]) - pt = curvePoint(crv, 0.0) + pt = HOHQMesh.curvePoint(crv, 0.0) @test isapprox(pt, [0.0, 0.0, 0.0]) # # The curvePoints for the spline has M = max(N,nKnots*2) values # M = max(nPts, nKnots*2) - pts = curvePoints(crv, M) + pts = HOHQMesh.curvePoints(crv, M) d = 1.0 / M for j in 1:M+1 tj = (j-1) * d diff --git a/test/test_examples.jl b/test/test_examples.jl index 901e8181..725d3e3f 100644 --- a/test/test_examples.jl +++ b/test/test_examples.jl @@ -4,7 +4,7 @@ using HOHQMesh using Test # We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used -# as a testing backend for HQMTool's Makie-based visualization. +# as a testing backend for interactive mesh tool's Makie-based visualization. #using CairoMakie @testset "Interactive Examples Tests" begin diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index aca6076f..6647e37f 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -1,4 +1,4 @@ -module TestHQMToolProject +module TestInteractiveMeshProject #= Project Tests tests the "Project.jl" functions @@ -51,7 +51,7 @@ using Test control_file = joinpath(HOHQMesh.examples_dir(), "AllFeatures.control") p = openProject(control_file, projectPath) - @test hasBackgroundGrid(p) == true + @test HOHQMesh.hasBackgroundGrid(p) == true bounds = [25.28, -20.0, -5.0, 20.0] @test isapprox(p.bounds,bounds) refinementNames = ["center", "line"] @@ -64,7 +64,7 @@ using Test xGrid = [-23.0, -20.0, -17.0, -14.0, -11.0, -8.0, -5.0, -2.0, 1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0, 22.0] yGrid = [-8.0, -5.0, -2.0, 1.0, 4.0, 7.0, 10.0, 13.0, 16.0, 19.0, 22.0, 25.0, 28.0] - p.xGrid, p.yGrid = projectGrid(p) + p.xGrid, p.yGrid = HOHQMesh.projectGrid(p) @test isapprox(p.xGrid,xGrid) @test isapprox(p.yGrid,yGrid) @@ -84,7 +84,7 @@ using Test @test isapprox( getBackgroundGridLowerLeft(p) , lower_left ) # Update the background grid starting point new_lower_left = [-25.0, -10.0, 0.0] - setBackgroundGridLowerLeft!(p, new_lower_left) + HOHQMesh.setBackgroundGridLowerLeft!(p, new_lower_left) @test isapprox( getBackgroundGridLowerLeft(p) , new_lower_left ) end diff --git a/test/test_project_with_viz.jl b/test/test_project_with_viz.jl index 8f446fcb..6b77cf52 100644 --- a/test/test_project_with_viz.jl +++ b/test/test_project_with_viz.jl @@ -4,7 +4,7 @@ using HOHQMesh using Test # We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used -# as a testing backend for HQMTool's Makie-based visualization. +# as a testing backend for interactive mesh tool's Makie-based visualization. using CairoMakie @testset "Project with Visualization Tests" begin @@ -36,7 +36,7 @@ using CairoMakie # Check the computed background grid against expected values x_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0] y_grid_control = [-8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] - p_scratch.xGrid, p_scratch.yGrid = projectGrid(p_scratch) + p_scratch.xGrid, p_scratch.yGrid = HOHQMesh.projectGrid(p_scratch) @test isapprox(p_scratch.xGrid, x_grid_control) @test isapprox(p_scratch.yGrid, y_grid_control) diff --git a/test/test_visualization.jl b/test/test_visualization.jl index 47734037..66bd6fa7 100644 --- a/test/test_visualization.jl +++ b/test/test_visualization.jl @@ -13,7 +13,7 @@ using HOHQMesh using Test # We use CairoMakie to avoid some CI-related issues with GLMakie. CairoMakie can be used -# as a testing backend for HQMTool's Makie-based visualization. +# as a testing backend for interactive mesh tool's Makie-based visualization. using CairoMakie @testset "Visualization Tests" begin From dd29e70ea91758d6981a83286c179236f8ed9df1 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 23 Jun 2022 12:14:06 +0200 Subject: [PATCH 161/164] remove unnecessary part of github docs --- docs/src/github-git.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/github-git.md b/docs/src/github-git.md index bef9991c..d2f761f5 100644 --- a/docs/src/github-git.md +++ b/docs/src/github-git.md @@ -96,7 +96,6 @@ review. That is, you should * remove debug statements * add a script `interactive_xxx.jl` that uses your feature (only relevant for new features within the interactive mesh funtionality) - * describe changes in `NEWS.md` if appropriate After you are confident that your branch is cleaned up properly, commit all changes and push them to the repository. From 1675a080ef69159665ab62833d5d670bb2d95795 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 23 Jun 2022 13:21:11 +0200 Subject: [PATCH 162/164] further cleanup of exporting --- src/HOHQMesh.jl | 35 +++++++++++++---------------------- src/Project/ModelAPI.jl | 20 +++++++++++++++++--- test/test_hqmtool_project.jl | 4 ++-- test/test_model.jl | 2 +- test/test_run_parameters.jl | 2 +- test/test_smoother.jl | 4 ++-- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/HOHQMesh.jl b/src/HOHQMesh.jl index 56b7d73b..58678810 100644 --- a/src/HOHQMesh.jl +++ b/src/HOHQMesh.jl @@ -54,28 +54,23 @@ include("Mesh/Meshing.jl") # or an interactive mesh `Project` export generate_mesh -# Generic functions for the interactice mesh interface +# +# Export the front facing interactive mesh functionality, e.g., getter/setter pairs. +# + +# Generic functions for the interactive mesh interface export new, add!, getCurve, getInnerBoundary, remove! -# -# Export the front facing interactive mesh functionality, e.g., getter/setter pairs. -# - # Functions from `BackgroundGridAPI.jl` export addBackgroundGrid!, removeBackgroundGrid!, setBackgroundGridSize!, getBackgroundGridSize, getBackgroundGridLowerLeft, getBackgroundGridSteps -# Functions from `ControlInputAPI.jl` -export getControlDict, - getDictInControlDictNamed, - getListInControlDictNamed - # Functions from `CurvesAPI.jl` export newParametricEquationCurve, newEndPointsLineCurve, @@ -97,27 +92,23 @@ export newParametricEquationCurve, setSplinePoints!, getSplinePoints # Functions from `ModelAPI.jl` -export addCurveToOuterBoundary!, removeOuterBoundaryCurveWithName!, +export addCurveToOuterBoundary!, + removeOuterBoundaryCurveWithName!, removeOuterBoundaryCurveAtIndex!, getOuterBoundaryCurveWithName, - insertOuterBoundaryCurveAtIndex!, removeOuterBoundaryCurveAtIndex!, + insertOuterBoundaryCurveAtIndex!, addOuterBoundary!, removeOuterBoundary!, getOuterBoundaryChainList, - addCurveToInnerBoundary!, removeInnerBoundaryCurve!, - insertInnerBoundaryCurveAtIndex!, removeInnerBoundaryCurveAtIndex!, + addCurveToInnerBoundary!, + removeInnerBoundaryCurve!, removeInnerBoundaryCurveAtIndex!, + insertInnerBoundaryCurveAtIndex!, removeInnerBoundary!, addInnerBoundaryWithName!, getChainIndex, - getAllInnerBoundaries, getInnerBoundaryChainWithName, - getInnerBoundaryCurve, - innerBoundaryIndices, - getModelDict, - getDictInModelDictNamed + getInnerBoundaryCurve # Functions from `Project.jl` -export newProject, - openProject, - saveProject +export newProject, openProject, saveProject # Functions from `RefinementRegionsAPI.jl` export newRefinementCenter, diff --git a/src/Project/ModelAPI.jl b/src/Project/ModelAPI.jl index ea7e289b..bfa5ebc6 100644 --- a/src/Project/ModelAPI.jl +++ b/src/Project/ModelAPI.jl @@ -24,7 +24,7 @@ end """ removeOuterBoundaryCurveWithName!(proj::Project, name::String) -Remove the named curve in the outer boundary +Remove the named curve in the outer boundary. """ function removeOuterBoundaryCurveWithName!(proj::Project, name::String) lst = getOuterBoundaryChainList(proj) @@ -176,9 +176,9 @@ function addCurveToInnerBoundary!(proj::Project, crv::Dict{String,Any}, boundary end """ - removeInnerBoundaryCurve!(proj::Project, name::String) + removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) -Remove the named curve in the inner boundary +Remove the curve with `name` from an inner boundary chain with `chainName`. """ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::String) i, chain = getInnerBoundaryChainWithName(proj,chainName) @@ -209,6 +209,14 @@ function removeInnerBoundaryCurve!(proj::Project, name::String, chainName::Strin removeInnerBoundaryCurveAtIndex!(proj,indx,chainName) end + +""" + insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, + indx::Int, boundaryName::String) + +Insert a curve `crv` into an inner boundary chain `boundaryName` +at the specified index `indx`. +""" function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, indx::Int, boundaryName::String) i, chain = getInnerBoundaryChainWithName(proj,boundaryName) @@ -229,6 +237,12 @@ function insertInnerBoundaryCurveAtIndex!(proj::Project, crv::Dict{String,Any}, postNotificationWithName(proj,"MODEL_DID_CHANGE_NOTIFICATION",(nothing,)) end + +""" + removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) + +Remove the curve at index `indx` from an inner boundary chain with `chainName`. +""" function removeInnerBoundaryCurveAtIndex!(proj::Project, indx::Int, chainName::String) i, chain = getInnerBoundaryChainWithName(proj,chainName) lst = chain["LIST"] diff --git a/test/test_hqmtool_project.jl b/test/test_hqmtool_project.jl index 6647e37f..caa1c4cf 100644 --- a/test/test_hqmtool_project.jl +++ b/test/test_hqmtool_project.jl @@ -41,10 +41,10 @@ using Test @test getSmoothingStatus(q) == "ON" @test getSmoothingType(q) == "LinearAndCrossbarSpring" - cDict = getControlDict(q) + cDict = HOHQMesh.getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == true removeSpringSmoother!(q) - cDict = getControlDict(q) + cDict = HOHQMesh.getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == false # read in the AllFeatures example diff --git a/test/test_model.jl b/test/test_model.jl index 855f4721..7fa92f71 100644 --- a/test/test_model.jl +++ b/test/test_model.jl @@ -89,7 +89,7 @@ using Test @test_throws ErrorException removeOuterBoundaryCurveWithName!(p, "wrongName") removeOuterBoundary!(p) - mDict = getModelDict(p) + mDict = HOHQMesh.getModelDict(p) @test haskey(mDict,"OUTER_BOUNDARY") == false undo() @test haskey(mDict,"OUTER_BOUNDARY") == true diff --git a/test/test_run_parameters.jl b/test/test_run_parameters.jl index 84cba97b..8064bc69 100644 --- a/test/test_run_parameters.jl +++ b/test/test_run_parameters.jl @@ -83,7 +83,7 @@ using Test @test getPlotFileFormat(p) == "sem" removeRunParameters!(p) - cDict = getControlDict(p) + cDict = HOHQMesh.getControlDict(p) @test haskey(cDict,"RUN_PARAMETERS") == false end diff --git a/test/test_smoother.jl b/test/test_smoother.jl index deda0076..fd0eb522 100644 --- a/test/test_smoother.jl +++ b/test/test_smoother.jl @@ -51,10 +51,10 @@ using Test @test_logs (:warn, "Acceptable smoothers are: `LinearAndCrossbarSpring` or `LinearSpring`. Try again.") setSmoothingType!(q,"TorsionalSpring") @test getSmoothingType(q) == "LinearSpring" - cDict = getControlDict(q) + cDict = HOHQMesh.getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == true removeSpringSmoother!(q) - cDict = getControlDict(q) + cDict = HOHQMesh.getControlDict(q) @test haskey(cDict,"SPRING_SMOOTHER") == false end From 1907598147e40de039fb18f86147fdabf25c2b09 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 23 Jun 2022 13:28:11 +0200 Subject: [PATCH 163/164] update tests --- test/runtests.jl | 2 +- test/{test_hqmtool_project.jl => test_interactive_project.jl} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/{test_hqmtool_project.jl => test_interactive_project.jl} (100%) diff --git a/test/runtests.jl b/test/runtests.jl index 18349055..70ff58a8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -63,7 +63,7 @@ include("test_curve.jl") include("test_model.jl") # Interactive mesh project test routines -include("test_hqmtool_project.jl") +include("test_interactive_project.jl") # Interactive mesh scripts available in examples folder include("test_examples.jl") diff --git a/test/test_hqmtool_project.jl b/test/test_interactive_project.jl similarity index 100% rename from test/test_hqmtool_project.jl rename to test/test_interactive_project.jl From dde3e22364fda5948b300dc3506e69b603f62d19 Mon Sep 17 00:00:00 2001 From: Andrew Winters Date: Thu, 23 Jun 2022 20:31:24 +0200 Subject: [PATCH 164/164] add creation of output folder if not present --- docs/src/interactive_overview.md | 2 +- src/Project/Project.jl | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/src/interactive_overview.md b/docs/src/interactive_overview.md index 3f873d5c..52524826 100644 --- a/docs/src/interactive_overview.md +++ b/docs/src/interactive_overview.md @@ -8,7 +8,7 @@ meshing project interactively while graphically displaying the results. Several scripts are available in the `examples` folder to get you started. These example scripts follow the naming convention of `interactive_*` where the phrase interactive indicates their association with this API and then trailing information -will indicate what that script demonstrates. For instance, the file `interactive_splines.jl` +will indicate what that script demonstrates. For instance, the file `interactive_spline_curves.jl` provides an interactive project that creates an manipulates splines for the inner boundaries before generating the mesh. diff --git a/src/Project/Project.jl b/src/Project/Project.jl index 3ab31a16..dc42e445 100644 --- a/src/Project/Project.jl +++ b/src/Project/Project.jl @@ -131,6 +131,13 @@ function newProject(name::String, folder::String) addRunParameters!(proj) addSpringSmoother!(proj) enableUndo() +# +# Create the output directory if it does not exist +# + if !isdir(abspath(normpath(folder))) + mkdir(abspath(normpath(folder))) + end + return proj end