diff --git a/matflow/__init__.py b/matflow/__init__.py index 034bee9b..8a63780f 100644 --- a/matflow/__init__.py +++ b/matflow/__init__.py @@ -34,6 +34,7 @@ gh_repo="matflow-new", template_components=template_components, scripts_dir="data.scripts", # relative to root package + jinja_templates_dir="data.jinja_templates", # relative to root package workflows_dir="data.workflows", # relative to root package config_options=config_options, demo_data_dir="matflow.data.demo_data", diff --git a/matflow/data/jinja_templates/__init__.py b/matflow/data/jinja_templates/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/matflow/data/jinja_templates/gmsh/plate_with_hole.geo b/matflow/data/jinja_templates/gmsh/plate_with_hole.geo new file mode 100644 index 00000000..e6c1c44e --- /dev/null +++ b/matflow/data/jinja_templates/gmsh/plate_with_hole.geo @@ -0,0 +1,164 @@ +//============================================================================== +// Gmsh 3D parametric plate with hole mesh +// author: Lloyd Fletcher (scepticalrabbit) +//============================================================================== +// Always set to OpenCASCADE - circles and boolean opts are much easier! +SetFactory("OpenCASCADE"); + +// Allows gmsh to print to terminal in vscode - easier debugging +General.Terminal = 1; + +// View options - not required when +Geometry.PointLabels = 0; +Geometry.CurveLabels = 0; +Geometry.SurfaceLabels = 1; +Geometry.VolumeLabels = 0; + +//------------------------------------------------------------------------------ +// Variables +file_name = "case23.msh"; + +// Geometric variables +plate_width = {{ plate_width }}; +plate_diff = {{ plate_diff }}; // Must be positive +plate_height = plate_width+plate_diff; +plate_thick = {{ plate_thickness }}; + +hole_rad = {{ hole_diameter }}/2; +hole_loc_x = plate_width/2; +hole_loc_y = plate_height/2; +hole_circ = 2*Pi*hole_rad; + +// Mesh variables +elem_order = 1; + +plate_thick_layers = {{ plate_thick_layers }}; +hole_sect_nodes = {{ hole_sect_nodes }}; // Must be odd +plate_rad_nodes = {{ plate_radial_nodes }}; +plate_diff_nodes = {{ plate_diff_nodes }}; // numbers of nodes along the rectangular extension +plate_edge_nodes = Floor((hole_sect_nodes-1)/2)+1; +elem_size = hole_circ/(4*(hole_sect_nodes-1)); +tol = elem_size; // Used for bounding box selection tolerance +tol_thick = plate_thick/(4*plate_thick_layers); + +//------------------------------------------------------------------------------ +// Geometry Definition + +// Split plate into eight pieces with a square around the hole to allow spider +// web meshing around the hole +s1 = news; +Rectangle(s1) = {0.0,0.0,0.0, + plate_width/2,plate_diff/2}; +s2 = news; +Rectangle(s2) = {plate_width/2,0.0,0.0, + plate_width/2,plate_diff/2}; + +s3 = news; +Rectangle(s3) = {0.0,plate_diff/2,0.0, + plate_width/2,plate_width/2}; +s4 = news; +Rectangle(s4) = {plate_width/2,plate_diff/2,0.0, + plate_width/2,plate_width/2}; + +s5 = news; +Rectangle(s5) = {0.0,plate_width/2+plate_diff/2,0.0, + plate_width/2,plate_width/2}; +s6 = news; +Rectangle(s6) = {plate_width/2,plate_width/2+plate_diff/2,0.0, + plate_width/2,plate_width/2}; + +s7 = news; +Rectangle(s7) = {0.0,plate_height-plate_diff/2,0.0, + plate_width/2,plate_diff/2}; +s8 = news; +Rectangle(s8) = {plate_width/2,plate_height-plate_diff/2,0.0, + plate_width/2,plate_diff/2}; + +// Merge coincicent edges of the four overlapping squares +BooleanFragments{ Surface{s1}; Delete; } + { Surface{s2,s3,s4,s5,s6,s7,s8}; Delete; } + +// Create the hole surface +c2 = newc; Circle(c2) = {hole_loc_x,hole_loc_y,0.0,hole_rad}; +cl2 = newcl; Curve Loop(cl2) = {c2}; +s9 = news; Plane Surface(s9) = {cl2}; +// Bore out the hole from the quarters of the plate +BooleanDifference{ Surface{s3,s4,s5,s6}; Delete; }{ Surface{s9}; Delete; } + +//------------------------------------------------------------------------------ +// Transfinite meshing (line element sizes and mapped meshing) +Transfinite Curve{31,24,26,28} = plate_rad_nodes; +Transfinite Curve{1,5,3,7,23,29,30,34,14,17,19,22} = plate_edge_nodes; +Transfinite Curve{32,33,25,27} = hole_sect_nodes; +Transfinite Curve{4,2,6,20,18,21} = plate_diff_nodes; + +// NOTE: recombine surface turns default triangles into quads + +Transfinite Surface{s1} = {1,2,3,4}; +Recombine Surface{s1}; +Transfinite Surface{s2} = {2,5,6,3}; +Recombine Surface{s2}; + +Transfinite Surface{s3} = {17,18,3,16}; +Recombine Surface{s3}; +Transfinite Surface{s4} = {18,19,20,3}; +Recombine Surface{s4}; +Transfinite Surface{s5} = {17,21,10,16}; +Recombine Surface{s5}; +Transfinite Surface{s6} = {19,21,10,20}; +Recombine Surface{s6}; + +Transfinite Surface{s7} = {11,10,13,14}; +Recombine Surface{s7}; +Transfinite Surface{s8} = {10,12,15,13}; +Recombine Surface{s8}; + +Extrude{0.0,0.0,plate_thick}{ + Surface{:}; Layers{plate_thick_layers}; Recombine; +} + +//------------------------------------------------------------------------------ +// Physical lines and surfaces for export/BCs +Physical Volume("plate-vol") = {Volume{:}}; + +ps1() = Surface In BoundingBox{ + 0.0-tol,plate_height-tol,0.0-tol, + plate_width+tol,plate_height+tol,plate_thick+tol}; +Physical Surface("bc-top-disp") = {ps1(0),ps1(1)}; + +ps2() = Surface In BoundingBox{ + 0.0-tol,0.0-tol,0.0-tol, + plate_width+tol,0.0+tol,plate_thick+tol}; +Physical Surface("bc-base-disp") = {ps2(0),ps2(1)}; + +ps3() = Surface In BoundingBox{ + 0.0-tol,0.0-tol,plate_thick-tol_thick, + plate_width+tol,plate_height+tol,plate_thick+tol_thick}; +Physical Surface("plate-surf-vis-front") = {ps3(0),ps3(1),ps3(2),ps3(3), + ps3(4),ps3(5),ps3(6),ps3(7)}; + +ps4() = Surface In BoundingBox{ + 0.0-tol,0.0-tol,0.0-tol_thick, + plate_width+tol,plate_height+tol,0.0+tol_thick}; +Physical Surface("plate-surf-vis-back") = {ps4(0),ps4(1),ps4(2),ps4(3), + ps4(4),ps4(5),ps4(6),ps4(7)}; + +//------------------------------------------------------------------------------ +// Global meshing +num_threads = 4; + +Mesh.Algorithm = 6; +Mesh.Algorithm3D = 10; + +General.NumThreads = num_threads; +Mesh.MaxNumThreads1D = num_threads; +Mesh.MaxNumThreads2D = num_threads; +Mesh.MaxNumThreads3D = num_threads; + +Mesh.ElementOrder = elem_order; +Mesh 3; + +//------------------------------------------------------------------------------ +// Save and exit +// Save Str(file_name); +// Exit; diff --git a/matflow/data/programs/__init__.py b/matflow/data/programs/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/matflow/data/scripts/gmsh/generate_geo.py b/matflow/data/scripts/gmsh/generate_geo.py new file mode 100644 index 00000000..9b702c64 --- /dev/null +++ b/matflow/data/scripts/gmsh/generate_geo.py @@ -0,0 +1,179 @@ +from pathlib import Path + + +_PLATE_WITH_HOLE = """\ +//============================================================================== +// Gmsh 3D parametric plate with hole mesh +// author: Lloyd Fletcher (scepticalrabbit) +//============================================================================== +// Always set to OpenCASCADE - circles and boolean opts are much easier! +SetFactory("OpenCASCADE"); + +// Allows gmsh to print to terminal in vscode - easier debugging +General.Terminal = 1; + +// View options - not required when +Geometry.PointLabels = 0; +Geometry.CurveLabels = 0; +Geometry.SurfaceLabels = 1; +Geometry.VolumeLabels = 0; + +//------------------------------------------------------------------------------ +// Variables +file_name = "plate_with_hole.msh"; + +// Geometric variables +plate_width = {plate_width}; +plate_diff = {plate_diff}; // Must be positive +plate_height = plate_width+plate_diff; +plate_thick = {plate_thickness}; + +hole_rad = {hole_diameter}/2; +hole_loc_x = plate_width/2; +hole_loc_y = plate_height/2; +hole_circ = 2*Pi*hole_rad; + +// Mesh variables +elem_order = 1; + +plate_thick_layers = {plate_thick_layers}; +hole_sect_nodes = {hole_sect_nodes}; // Must be odd +plate_rad_nodes = {plate_radial_nodes}; +plate_diff_nodes = {plate_diff_nodes}; // numbers of nodes along the rectangular extension +plate_edge_nodes = Floor((hole_sect_nodes-1)/2)+1; +elem_size = hole_circ/(4*(hole_sect_nodes-1)); +tol = elem_size; // Used for bounding box selection tolerance +tol_thick = plate_thick/(4*plate_thick_layers); + +//------------------------------------------------------------------------------ +// Geometry Definition + +// Split plate into eight pieces with a square around the hole to allow spider +// web meshing around the hole +s1 = news; +Rectangle(s1) = {{0.0,0.0,0.0, + plate_width/2,plate_diff/2}}; +s2 = news; +Rectangle(s2) = {{plate_width/2,0.0,0.0, + plate_width/2,plate_diff/2}}; + +s3 = news; +Rectangle(s3) = {{0.0,plate_diff/2,0.0, + plate_width/2,plate_width/2}}; +s4 = news; +Rectangle(s4) = {{plate_width/2,plate_diff/2,0.0, + plate_width/2,plate_width/2}}; + +s5 = news; +Rectangle(s5) = {{0.0,plate_width/2+plate_diff/2,0.0, + plate_width/2,plate_width/2}}; +s6 = news; +Rectangle(s6) = {{plate_width/2,plate_width/2+plate_diff/2,0.0, + plate_width/2,plate_width/2}}; + +s7 = news; +Rectangle(s7) = {{0.0,plate_height-plate_diff/2,0.0, + plate_width/2,plate_diff/2}}; +s8 = news; +Rectangle(s8) = {{plate_width/2,plate_height-plate_diff/2,0.0, + plate_width/2,plate_diff/2}}; + +// Merge coincicent edges of the four overlapping squares +BooleanFragments{{ Surface{{s1}}; Delete; }} + {{ Surface{{s2,s3,s4,s5,s6,s7,s8}}; Delete; }} + +// Create the hole surface +c2 = newc; Circle(c2) = {{hole_loc_x,hole_loc_y,0.0,hole_rad}}; +cl2 = newcl; Curve Loop(cl2) = {{c2}}; +s9 = news; Plane Surface(s9) = {{cl2}}; +// Bore out the hole from the quarters of the plate +BooleanDifference{{ Surface{{s3,s4,s5,s6}}; Delete; }}{{ Surface{{s9}}; Delete; }} + +//------------------------------------------------------------------------------ +// Transfinite meshing (line element sizes and mapped meshing) +Transfinite Curve{{31,24,26,28}} = plate_rad_nodes; +Transfinite Curve{{1,5,3,7,23,29,30,34,14,17,19,22}} = plate_edge_nodes; +Transfinite Curve{{32,33,25,27}} = hole_sect_nodes; +Transfinite Curve{{4,2,6,20,18,21}} = plate_diff_nodes; + +// NOTE: recombine surface turns default triangles into quads + +Transfinite Surface{{s1}} = {{1,2,3,4}}; +Recombine Surface{{s1}}; +Transfinite Surface{{s2}} = {{2,5,6,3}}; +Recombine Surface{{s2}}; + +Transfinite Surface{{s3}} = {{17,18,3,16}}; +Recombine Surface{{s3}}; +Transfinite Surface{{s4}} = {{18,19,20,3}}; +Recombine Surface{{s4}}; +Transfinite Surface{{s5}} = {{17,21,10,16}}; +Recombine Surface{{s5}}; +Transfinite Surface{{s6}} = {{19,21,10,20}}; +Recombine Surface{{s6}}; + +Transfinite Surface{{s7}} = {{11,10,13,14}}; +Recombine Surface{{s7}}; +Transfinite Surface{{s8}} = {{10,12,15,13}}; +Recombine Surface{{s8}}; + +Extrude{{0.0,0.0,plate_thick}}{{ + Surface{{:}}; Layers{{plate_thick_layers}}; Recombine; +}} + +//------------------------------------------------------------------------------ +// Physical lines and surfaces for export/BCs +Physical Volume("plate-vol") = {{Volume{{:}}}}; + +ps1() = Surface In BoundingBox{{ + 0.0-tol,plate_height-tol,0.0-tol, + plate_width+tol,plate_height+tol,plate_thick+tol}}; +Physical Surface("bc-top-disp") = {{ps1(0),ps1(1)}}; + +ps2() = Surface In BoundingBox{{ + 0.0-tol,0.0-tol,0.0-tol, + plate_width+tol,0.0+tol,plate_thick+tol}}; +Physical Surface("bc-base-disp") = {{ps2(0),ps2(1)}}; + +ps3() = Surface In BoundingBox{{ + 0.0-tol,0.0-tol,plate_thick-tol_thick, + plate_width+tol,plate_height+tol,plate_thick+tol_thick}}; +Physical Surface("plate-surf-vis-front") = {{ps3(0),ps3(1),ps3(2),ps3(3), + ps3(4),ps3(5),ps3(6),ps3(7)}}; + +ps4() = Surface In BoundingBox{{ + 0.0-tol,0.0-tol,0.0-tol_thick, + plate_width+tol,plate_height+tol,0.0+tol_thick}}; +Physical Surface("plate-surf-vis-back") = {{ps4(0),ps4(1),ps4(2),ps4(3), + ps4(4),ps4(5),ps4(6),ps4(7)}}; + +//------------------------------------------------------------------------------ +// Global meshing +num_threads = 4; + +Mesh.Algorithm = 6; +Mesh.Algorithm3D = 10; + +General.NumThreads = num_threads; +Mesh.MaxNumThreads1D = num_threads; +Mesh.MaxNumThreads2D = num_threads; +Mesh.MaxNumThreads3D = num_threads; + +Mesh.ElementOrder = elem_order; +Mesh 3; + +//------------------------------------------------------------------------------ +// Save and exit +Save Str(file_name); +Exit; +""" + +_LOOKUP = { + "plate_with_hole": _PLATE_WITH_HOLE, +} + + +def generate_geo(path, geometry_name, **kwargs): + """Generate a Gmsh .geo file for generating a mesh of a plate with a hole.""" + with Path(path).open("wt") as fh: + fh.write(_LOOKUP[geometry_name.lower()].format(**kwargs)) diff --git a/matflow/data/scripts/gmsh/run_geo.py b/matflow/data/scripts/gmsh/run_geo.py new file mode 100644 index 00000000..5b5227db --- /dev/null +++ b/matflow/data/scripts/gmsh/run_geo.py @@ -0,0 +1,21 @@ +from pathlib import Path +import gmsh + + +def run_geo(gmsh_geo_file): + + # Initialize Gmsh + gmsh.initialize() + + # Run the .geo file + gmsh.open(gmsh_geo_file) + gmsh.write("mesh.msh") + + # Finalize Gmsh + gmsh.finalize() + + file = Path("mesh.msh") + with file.open("rt") as fh: + string = fh.read() + + return {"gmsh_mesh_str": string} diff --git a/matflow/data/scripts/moose/__init__.py b/matflow/data/scripts/moose/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/matflow/data/scripts/moose/dump_mesh.py b/matflow/data/scripts/moose/dump_mesh.py new file mode 100644 index 00000000..4754f7e6 --- /dev/null +++ b/matflow/data/scripts/moose/dump_mesh.py @@ -0,0 +1,6 @@ +from pathlib import Path + + +def dump_mesh(path, gmsh_mesh_str): + with Path("mesh.msh").open("wt", newline="\n") as fh: + fh.write(gmsh_mesh_str) diff --git a/matflow/data/scripts/moose/write_input.py b/matflow/data/scripts/moose/write_input.py new file mode 100644 index 00000000..eafb3495 --- /dev/null +++ b/matflow/data/scripts/moose/write_input.py @@ -0,0 +1,48 @@ +from pathlib import Path + + +class MooseBlock: + TAB = " " + + def __init__(self, name, collection, root=False, variables=None): + self.name = name + self.root = root + self.attributes = {} + self.blocks = [] + self.variables = variables or {} + + for key, val in collection.items(): + # if isinstance(val, CommentedMap): + if isinstance(val, dict): + self.blocks.append(MooseBlock(key, val)) + continue + self.attributes[key] = val + + def __str__(self) -> str: + if self.root: + tab = "" + txt = "" + for key, val in self.variables.items(): + txt += f"{key} = {val}\n" + else: + tab = self.TAB + txt = f"[{self.name}]\n" + + for key, val in self.attributes.items(): + txt += f"{tab}{key} = {val}\n" + for block in self.blocks: + txt += tab + txt += str(block).replace("\n", f"\n{tab}") + txt = txt[: len(txt) - len(tab)] + if not self.root: + txt += "[]\n" + return txt + + def to_file(self, path: Path): + with path.open("wt", newline="\n") as f: + f.write(self.__str__()) + + +def write_input(path, input_deck, input_deck_variables): + input_deck = MooseBlock("root", input_deck, root=True, variables=input_deck_variables) + input_deck.to_file(path) diff --git a/matflow/data/template_components/command_files.yaml b/matflow/data/template_components/command_files.yaml index 9c181f30..da1cc5b5 100644 --- a/matflow/data/template_components/command_files.yaml +++ b/matflow/data/template_components/command_files.yaml @@ -69,3 +69,7 @@ name: name: pipeline.xdmf doc: DREAM.3D model data and metadata. + +- label: moose_input_deck + name: + name: input.i diff --git a/matflow/data/template_components/parameters.yaml b/matflow/data/template_components/parameters.yaml index 2b5c9c45..188ef87a 100644 --- a/matflow/data/template_components/parameters.yaml +++ b/matflow/data/template_components/parameters.yaml @@ -90,16 +90,16 @@ and: - value.is_instance: [dict] - key.in: - - "type" - - "name" - - "crystal_structure" - - "volume_fraction" - - "size_distribution" - - "radial_distribution_function" - - "number_fraction_on_boundary" - - "preset_statistics_model" - - "ODF" - - "axis_ODF" + - "type" + - "name" + - "crystal_structure" + - "volume_fraction" + - "size_distribution" + - "radial_distribution_function" + - "number_fraction_on_boundary" + - "preset_statistics_model" + - "ODF" + - "axis_ODF" - path: [{ "type": "list_value" }, "type"] condition: and: @@ -149,7 +149,8 @@ condition: and: - value.is_instance: [dict] - - key.in: ["filename", "crop", "scale", "homog_points", "min_grain_size"] + - key.in: + ["filename", "crop", "scale", "homog_points", "min_grain_size"] - type: EBSD _validation: - path: [] @@ -157,7 +158,8 @@ condition: and: - value.is_instance: [dict] - - key.in: ["filename", "boundary_tol", "min_grain_size", "homog_points"] + - key.in: + ["filename", "boundary_tol", "min_grain_size", "homog_points"] - type: EBSD_phase _validation: - path: [] @@ -171,11 +173,11 @@ and: - value.is_instance: [str] - value.in: - - euler_to_spatial - - spatial_to_euler - # https://mtex-toolbox.github.io/EBSDReferenceFrame.html - - convertEuler2SpatialReferenceFrame - - convertSpatial2EulerReferenceFrame + - euler_to_spatial + - spatial_to_euler + # https://mtex-toolbox.github.io/EBSDReferenceFrame.html + - convertEuler2SpatialReferenceFrame + - convertSpatial2EulerReferenceFrame - type: EBSD_rotation _validation: - path: [] @@ -185,7 +187,7 @@ condition: and: - value.is_instance: [dict] - - key.in: [ "euler_angles_deg", "keep_XY", "keep_euler" ] + - key.in: ["euler_angles_deg", "keep_XY", "keep_euler"] - type: num_orientations _validation: - path: [] @@ -221,14 +223,14 @@ or `"incremental_data"` (now deprecated). condition: and: - - value.is_instance: [dict] - - key.in: - - "geom_path" - - "incremental_data" - - "volume_data" - - "phase_data" - - "field_data" - - "grain_data" + - value.is_instance: [dict] + - key.in: + - "geom_path" + - "incremental_data" + - "volume_data" + - "phase_data" + - "field_data" + - "grain_data" - type: homogenization _validation: - path: [] @@ -259,33 +261,33 @@ and: - value.is_instance: [dict] - key.in: ["name", "args", "opts"] - - path: [{ "type": "list_value" }, "name" ] + - path: [{ "type": "list_value" }, "name"] doc: See `damask.Result` for what the operations do. condition: and: - value.is_instance: [str] - value.in: - # I think these are the relevant operations - - "add_absolute" - - "add_calculation" - - "add_stress_Cauchy" - - "add_determinant" - - "add_deviator" - - "add_eigenvalue" - - "add_eigenvector" - - "add_IPF_color" - - "add_maximum_shear" - - "add_equivalent_Mises" - - "add_norm" - - "add_stress_second_Piola_Kirchhoff" - - "add_pole" - - "add_rotation" - - "add_spherical" - - "add_strain" - - "add_stretch_tensor" - - "add_curl" - - "add_divergence" - - "add_gradient" + # I think these are the relevant operations + - "add_absolute" + - "add_calculation" + - "add_stress_Cauchy" + - "add_determinant" + - "add_deviator" + - "add_eigenvalue" + - "add_eigenvector" + - "add_IPF_color" + - "add_maximum_shear" + - "add_equivalent_Mises" + - "add_norm" + - "add_stress_second_Piola_Kirchhoff" + - "add_pole" + - "add_rotation" + - "add_spherical" + - "add_strain" + - "add_stretch_tensor" + - "add_curl" + - "add_divergence" + - "add_gradient" - type: damask_viz _validation: - path: [] @@ -296,8 +298,8 @@ condition: or: - and: - - value.is_instance: [dict] - - key.in: ["increments", "phases", "homogenizations", "fields"] + - value.is_instance: [dict] + - key.in: ["increments", "phases", "homogenizations", "fields"] - value.is_instance: [list] - type: damask_solver _validation: @@ -324,7 +326,7 @@ - type: dump_path _validation: - path: [] - doc: Where to write dump data. + doc: Where to write dump data. condition: { value.is_instance: [str, path] } - type: yield_point # vol-avg equivalent plastic strain _validation: @@ -451,13 +453,13 @@ - value.is_instance: [list] - value.length.equal_to: 3 - path: [{ "type": "list_value" }] - condition: { value.is_instance: [int, float]} + condition: { value.is_instance: [int, float] } - type: resolution _validation: - path: [] condition: { value.is_instance: [list] } - path: [{ "type": "list_value" }] - condition: { value.is_instance: [int, float]} + condition: { value.is_instance: [int, float] } - type: levenberg_marquardt_fitter _validation: - path: [] @@ -475,7 +477,7 @@ - path: [] condition: { value.is_instance: [list] } - path: [{ "type": "list_value" }] - condition: { value.is_instance: [str]} + condition: { value.is_instance: [str] } - type: find_grains_algorithm _validation: - path: [] @@ -487,8 +489,7 @@ _validation: - path: [] doc: - description: - Single parameter to make an instance of MTEX `crystalSymmetry`. + description: Single parameter to make an instance of MTEX `crystalSymmetry`. examples: - "`cubic` - Cubic symmetry" - "`hexagonal` - Hexagonal symmetry" @@ -505,7 +506,7 @@ - value.is_instance: [list] - value.length.equal_to: 3 - path: [{ "type": "list_value" }, { "type": "list_value" }] - condition: { value.is_instance: [int, float]} + condition: { value.is_instance: [int, float] } - type: IPF_reference_direction _validation: - path: [] @@ -522,7 +523,7 @@ - value.is_instance: [list] - value.length.equal_to: 2 - path: [{ "type": "list_value" }] - condition: { value.is_instance: [float]} + condition: { value.is_instance: [float] } - type: ODF_components _validation: - path: [] @@ -531,7 +532,7 @@ and: - value.is_instance: [list] - path: [{ "type": "list_value" }] - condition: { value.is_instance: [dict]} + condition: { value.is_instance: [dict] } - type: order _validation: - path: [] @@ -556,7 +557,7 @@ - value.is_instance: [list] - value.length.equal_to: 6 - path: [{ "type": "list_value" }] - condition: { value.is_instance: [int]} + condition: { value.is_instance: [int] } - type: phase_ids _validation: - path: [] @@ -567,7 +568,7 @@ - value.is_instance: [list] - value.length.equal_to: 6 - path: [{ "type": "list_value" }] - condition: { value.is_instance: [int]} + condition: { value.is_instance: [int] } - type: phase_labels _validation: - path: [] @@ -578,7 +579,7 @@ - value.is_instance: [list] - value.length.equal_to: 6 - path: [{ "type": "list_value" }] - condition: { value.is_instance: [str]} + condition: { value.is_instance: [str] } - type: phase_label_mapping _validation: - path: [] @@ -600,3 +601,4 @@ - type: single_crystal_parameters - type: tensile_test - type: yield_point_criteria +- type: input_deck diff --git a/matflow/data/workflows/generate_gmsh_mesh.yaml b/matflow/data/workflows/generate_gmsh_mesh.yaml new file mode 100644 index 00000000..2dcee49b --- /dev/null +++ b/matflow/data/workflows/generate_gmsh_mesh.yaml @@ -0,0 +1,113 @@ +doc: + - | + WIP: Initial workflow development for a specific MOOSE workflow: mesh-refinement of a + plate with a hole. + - | + TODO: support in hpcflow `InputFileGenerator.from_input_files` so we can pass the .geo + script to the second IFG that generates the .msh file from that geo file. This will + then enable passing a pre-written .geo file, and skipping the first IFG. + - | + TODO: support in hpcflow a `templates` data directory, and then ability to generate + an input file from a specified template, using possibly jinja. Support the ability to + substitute input parameters within the template path (e.g. + `<>>>`), like we currently support with + environment specifiers (`<>/script.py>>`). + - | + Note: the `gmsh_env` environment should be a Python environment (with a `python_script` + executable) that has `gmsh` installed (from PyPI or Conda). + +template_components: + environments: + + command_files: + - label: gmsh_geo_file + name: + name: script.geo + doc: Gmsh geometry script file. + - label: gmsh_mesh_file + name: + name: (.*\.msh) + is_regex: true + doc: Gmsh mesh file, typically generated from a Gmsh .geo script. + task_schemas: + - objective: generate_mesh + method: gmsh + inputs: + - parameter: geometry_name + - parameter: plate_width + default_value: 100e-3 + - parameter: plate_thickness + default_value: 2e-3 + - parameter: hole_diameter + default_value: 25e-3 + - parameter: plate_thick_layers + default_value: 2 + - parameter: hole_sect_nodes + default_value: 9 # must be odd; number of nodes around a quadrant of the circumference of the hole + - parameter: plate_radial_nodes + default_value: 9 # number of nodes from the hole to the edges of the central section + - parameter: plate_diff + default_value: 50e-3 # length of rectangular extension + - parameter: plate_diff_nodes + default_value: 5 # number of nodes along the rectangular extension + outputs: + - parameter: gmsh_mesh_str + actions: + - environments: + any: gmsh_env + input_file_generators: + - input_file: gmsh_geo_file + from_inputs: + - geometry_name + - plate_width + - plate_thickness + - hole_diameter + - plate_thick_layers + - hole_sect_nodes + - plate_radial_nodes + - plate_diff_nodes + - plate_diff + jinja_template: gmsh/<>.geo + script: <> + script_exe: python_script + script_data_in: + input_files.gmsh_geo_file: direct + script_data_out: + outputs.gmsh_mesh_str: direct + requires_dir: true + +# instead, we need: +# task: generate_mesh with gmsh (via .geo file) +# - render jinja template to .geo file +# - execute .geo script with gmsh Python API to generate either a .msh or the mesh data +# - if generated a .msh, parse to a parameter +# - would also want to be able to pass a complete .geo file as well (as input_files: ...) + +config: + log_file_level: debug + +resources: + any: + write_app_logs: true + +tasks: + - schema: generate_mesh_gmsh + # input_files: + # gmsh_geo_file: D:/scratch/script.geo + inputs: + geometry_name: plate_with_hole + plate_width: 100e-3 + plate_thickness: 2e-3 + hole_diameter: 25e-3 + plate_thick_layers: 2 + # hole_sect_nodes: 9 + # plate_radial_nodes: 9 + # plate_diff_nodes: 5 + plate_diff: 50e-3 + # sequences: + # - path: inputs.hole_sect_nodes # must be odd! + # values: [5, 9, 13] + # - path: inputs.plate_radial_nodes + # values: [5, 9, 13] + # - path: inputs.plate_diff_nodes + # values: [5, 9, 13] diff --git a/matflow/data/workflows/moose_plate.yaml b/matflow/data/workflows/moose_plate.yaml new file mode 100644 index 00000000..5acad9bf --- /dev/null +++ b/matflow/data/workflows/moose_plate.yaml @@ -0,0 +1,197 @@ +template_components: + command_files: + - label: gmsh_geo_file + name: + name: script.geo + doc: Gmsh geometry script file. + - label: gmsh_mesh_file + name: + name: (.*\.msh) + is_regex: true + doc: Gmsh mesh file, typically generated from a Gmsh .geo script. + task_schemas: + - objective: generate_mesh + method: gmsh + inputs: + - parameter: geometry_name + - parameter: plate_width + default_value: 100e-3 + - parameter: plate_thickness + default_value: 2e-3 + - parameter: hole_diameter + default_value: 25e-3 + - parameter: plate_thick_layers + default_value: 2 + - parameter: hole_sect_nodes + default_value: 9 # must be odd; number of nodes around a quadrant of the circumference of the hole + - parameter: plate_radial_nodes + default_value: 9 # number of nodes from the hole to the edges of the central section + - parameter: plate_diff + default_value: 50e-3 # length of rectangular extension + - parameter: plate_diff_nodes + default_value: 5 # number of nodes along the rectangular extension + outputs: + - parameter: gmsh_mesh_str + actions: + - environments: + any: gmsh_env + input_file_generators: + - input_file: gmsh_geo_file + from_inputs: + - geometry_name + - plate_width + - plate_thickness + - hole_diameter + - plate_thick_layers + - hole_sect_nodes + - plate_radial_nodes + - plate_diff_nodes + - plate_diff + jinja_template: gmsh/<>.geo + script: <> + script_exe: python_script + script_data_in: + input_files.gmsh_geo_file: direct + script_data_out: + outputs.gmsh_mesh_str: direct + requires_dir: true + + - objective: simulation + implementation: moose + inputs: + - parameter: gmsh_mesh_str + - parameter: input_deck + - parameter: input_deck_variables + default_value: null + actions: + - environments: + any: python_env + main: moose_env + input_file_generators: + - input_file: gmsh_mesh_file + from_inputs: [gmsh_mesh_str] + script: <> + - input_file: moose_input_deck + from_inputs: [input_deck, input_deck_variables] + script_data_in: + input_deck: direct + script: <> + abortable: true + commands: + - command: <> -i input.i + stdout: stdout.log + stderr: stderr.log + +tasks: + - schema: generate_mesh_gmsh + # input_files: + # gmsh_geo_file: D:/scratch/script.geo + inputs: + geometry_name: plate_with_hole + plate_width: 100e-3 + plate_thickness: 2e-3 + hole_diameter: 25e-3 + plate_thick_layers: 2 + # hole_sect_nodes: 9 + # plate_radial_nodes: 9 + # plate_diff_nodes: 5 + plate_diff: 50e-3 + + - schema: simulation_moose + resources: + main: + shell: wsl + inputs: + input_deck_variables: + endTime: 8 + timeStep: 1 + # Mechanical Loads/BCs + topDispRate: ${fparse 1e-3 / endTime} # m/s + # Mechanical Props: SS316L @ 20degC + ss316LEMod: 200e9 # Pa + ss316LPRatio: 0.3 # - + input_deck: + GlobalParams: + displacements: "'disp_x disp_y disp_z'" + Mesh: + type: FileMesh + file: mesh.msh + Modules/TensorMechanics/Master: + all: + strain: SMALL + incremental: true + add_variables: true + material_output_family: MONOMIAL # MONOMIAL, LAGRANGE + material_output_order: FIRST # CONSTANT, FIRST, SECOND, + generate_output: "'vonmises_stress strain_xx strain_xy strain_xz strain_yx strain_yy strain_yz strain_zx strain_zy strain_zz stress_xx stress_xy stress_xz stress_yx stress_yy stress_yz stress_zx stress_zy stress_zz max_principal_strain mid_principal_strain min_principal_strain'" + BCs: + bottom_x: + type: DirichletBC + variable: disp_x + boundary: "'bc-base-disp'" + value: 0.0 + bottom_y: + type: DirichletBC + variable: disp_y + boundary: "'bc-base-disp'" + value: 0.0 + bottom_z: + type: DirichletBC + variable: disp_z + boundary: "'bc-base-disp'" + value: 0.0 + top_x: + type: DirichletBC + variable: disp_x + boundary: "'bc-top-disp'" + value: 0.0 + top_y: + type: FunctionDirichletBC + variable: disp_y + boundary: "'bc-top-disp'" + function: "'${topDispRate}*t'" + top_z: + type: DirichletBC + variable: disp_z + boundary: "'bc-top-disp'" + value: 0.0 + Materials: + elasticity: + type: ComputeIsotropicElasticityTensor + youngs_modulus: ${ss316LEMod} + poissons_ratio: ${ss316LPRatio} + stress: + type: ComputeFiniteStrainElasticStress + Preconditioning: + SMP: + type: SMP + full: true + Executioner: + type: Transient + solve_type: "'PJFNK'" + petsc_options_iname: "'-pc_type -pc_hypre_type'" + petsc_options_value: "'hypre boomeramg'" + end_time: ${endTime} + dt: ${timeStep} + Postprocessors: + react_y_bot: + type: SidesetReaction + direction: "'0 1 0'" + stress_tensor: stress + boundary: "bc-base-disp" + react_y_top: + type: SidesetReaction + direction: "'0 1 0'" + stress_tensor: stress + boundary: "bc-top-disp" + disp_y_max: + type: NodalExtremeValue + variable: disp_y + disp_x_max: + type: NodalExtremeValue + variable: disp_x + disp_z_max: + type: NodalExtremeValue + variable: disp_x + Outputs: + exodus: true diff --git a/matflow/data/workflows/moose_test.yaml b/matflow/data/workflows/moose_test.yaml new file mode 100644 index 00000000..f06b28d1 --- /dev/null +++ b/matflow/data/workflows/moose_test.yaml @@ -0,0 +1,89 @@ +template_components: + task_schemas: + - objective: simulation + implementation: moose + inputs: + - parameter: input_deck + - parameter: input_deck_variables + default_value: null + actions: + - environments: + processing: python_env + main: moose_env + input_file_generators: + - input_file: moose_input_deck + from_inputs: [input_deck, input_deck_variables] + script: <> + abortable: true + commands: + - command: <> -i input.i + stdout: stdout.log + stderr: stderr.log + +tasks: + - schema: simulation_moose + # resources: + # main: + # num_cores: 2 + # scheduler_args: + # options: + # --time: 01:00:00 + # resources: + # main: + # shell: wsl + inputs: + input_deck: + Mesh: + generated: + type: GeneratedMeshGenerator + dim: 2 + nx: 10 + ny: 5 + xmax: 100e-3 + ymax: 50e-3 + elem_type: QUAD4 + Variables: + temperature: + initial_condition: 20.0 + Kernels: + heat_conduction: + type: HeatConduction + variable: temperature + Materials: + copper_thermal: + type: HeatConductionMaterial + thermal_conductivity: 384.0 + specific_heat: 406.0 + copper_density: + type: GenericConstantMaterial + prop_names: density + prop_values: 8829.0 + BCs: + heat_flux_out: + type: ConvectiveHeatFluxBC + variable: temperature + boundary: left + T_infinity: 20.0 + heat_transfer_coefficient: 125.0e3 + heat_flux_in: + type: NeumannBC + variable: temperature + boundary: right + value: 500.0e3 + Executioner: + type: Steady + Postprocessors: + max_temp: + type: NodalExtremeValue + variable: temperature + avg_temp: + type: AverageNodalVariableValue + variable: temperature + Outputs: + exodus: true + # sequences: + # - path: inputs.input_deck.BCs.heat_flux_out.heat_transfer_coefficient + # values::from_random_normal: + # mean: 125.0e3 + # std_dev: 5.0e3 + # num: 10