8. Insert Wells

In this step, we will generate two cylindrical 'wells', refine the mesh `MONAME` around them, and identify a line of nodes that will be the well source/sink for boundary conditions (ultimately writing these nodes to `zone` files). ### 8.1 Generating Cylindrical Tetrahedral Wells First, we define variables for the well's position (`XWELL`,`YWELL`), radius (`RADIUS_WELL`), and number of nodes across the cylindrical radius (`NRADIUS`): ``` define / XWELL1 / 1234.56 define / YWELL1 / 1987.65 define / XWELL2 / 2243.21 define / YWELL2 / 1212.34 define / RADIUS_WELL / 25.0 define / NRADIUS / 2 ``` Now, we create a cylindrical point cloud defining the first well using `createpts / rtz`: ``` cmo / create / mo_well1 / / / tet createpts / rtz / NRADIUS 9 NZ / 0. 0. 3100. / RADIUS_WELL 360. 1500. / 1 1 1 ``` This creates a point cloud centered around (0,0,0) with a radius of `RADIUS_WELL`, an angular component spanning a full 360 degrees (`φ = {0., 360.}`), and a Z range of `{3100.,1500.}`. Run `filter`, `rmpoint / compress`, and set `imt` to 1 for the well: ``` filter / 1 0 0 rmpoint / compress cmo / setatt / mo_well1 / imt / 1 0 0 / 1 ``` Next, connect the point cloud into a tetrahedral mesh and translate the X and Y origin to `{XWELL1,YWELL1}`: ``` connect resetpts / itp cmo / printatt / mo_well1 / -xyz- / minmax trans / 1 0 0 / 0. 0. 0. / XWELL1 YWELL1 0.0 cmo / printatt / mo_well1 / -xyz- / minmax ``` The first 'well' mesh object has been generated. Repeat this process with different parameters to create the second well: ``` cmo / create / mo_well2 / / / tet createpts / rtz / NRADIUS 9 NZ / 0. 0. 3100. / RADIUS_WELL 360. 2200. / 1 1 1 filter / 1 0 0 rmpoint / compress cmo / setatt / mo_well1 / imt / 1 0 0 / 1 connect resetpts / itp cmo / printatt / mo_well2 / -xyz- / minmax trans / 1 0 0 / 0. 0. 0. / XWELL2 YWELL2 0.0 cmo / printatt / mo_well2 / -xyz- / minmax ``` Finally, join the two distinct wells into a single mesh object with `addmesh / merge`: ``` addmesh / merge / mo_wells / mo_well1 mo_well2 ``` ### 8.2 Refining `MONAME` around the wells As we did for the fault in step 7, we refine the main mesh `MONAME` around the wells: ``` # First pass refinement cmo / select / MONAME intersect_elements / MONAME / mo_wells / if_inter eltset / e_refine / if_inter / gt / 0 refine/ eltset / eltset get e_refine cmo / setatt / MONAME / if_inter / 1 0 0 / 0 eltset / e_refine / delete # Second pass refinement cmo / select / MONAME intersect_elements / MONAME / mo_wells / if_inter eltset / e_refine / if_inter / gt / 0 refine/ eltset / eltset get e_refine cmo / setatt / MONAME / if_inter / 1 0 0 / 0 eltset / e_refine / delete # Third pass refinement cmo / select / MONAME intersect_elements / MONAME / mo_wells / if_inter eltset / e_refine / if_inter / gt / 0 refine/ eltset / eltset get e_refine cmo / setatt / MONAME / if_inter / 1 0 0 / 0 eltset / e_refine / delete ``` The refinement process returns a octree grid object, which stores information about parent-children relationships, among other properties. It's important, as the prepare to finalize the mesh for exporting, to strip this information and convert the octree grid object to a standard mesh object. This conversion is done through the `grid2grid / tree_to_fe` command: ``` grid2grid / tree_to_fe / mohex_octree / mohex define / MONAME / mohex_octree ```
### 8.3 Writing `zone` files based on well distances The `zone` files are lists of node numbers in [FEHM](https://fehm.lanl.gov) file format and used to identify materials, well source/sinks, and boundary conditions. In this subsection, we will generate `zone` files describing all nodes within 32, 16, 8, 4, 2 and 1 meters of the wells. To begin, we will compute the well point cloud again, as we did above. First, for well 1: ``` cmo / create / mo_pts1 createpts / rtz / 2 2 1000 / 0. 0. 3100. / 0.0 360. 2200. / 1 1 1 trans / 1 0 0 / 0. 0. 0. / XWELL1 YWELL1 0.0 ``` Then for well 2: ``` cmo / create / mo_pts2 createpts / rtz / 2 2 1000 / 0. 0. 3100. / 0.0 360. 2200. / 1 1 1 trans / 1 0 0 / 0. 0. 0. / XWELL2 YWELL2 0.0 ``` and joining them into a single mesh object, `mo_pts`: ``` addmesh / merge / mo_pts / mo_pts1 / mo_pts2 cmo / select / mo_pts filter / 1 0 0 rmpoint / compress ``` Next, we will compute a distance field attribute, `dfield_well`, which is a node-based attribute storing the Euclidean distance from `node_i` in one mesh to the closest node in another mesh. In other words, all nodes in `MONAME` store their distance to the closest well (`mo_pts`) node. ``` compute / distance_field / MONAME / mo_pts / dfield_well ``` Clean up unneeded mesh objects: ``` cmo / delete / mo_pts1 cmo / delete / mo_pts2 cmo / delete / mo_pts cmo / delete / mo_wells cmo / delete / mo_well1 cmo / delete / mo_well2 ``` And finally, for each mesh-to-well distance in {32,16,8,4,2,1} (which is stored in `dfield_well`), (i) create a pset object containing all nodes within that distance, and (ii) write those nodes to a `zone` file: ``` cmo / select / MONAME pset / pwell / attribute / dfield_well / 1 0 0 / le / 1.0 pset / pwell / zone / zone_radius_01.0.zone pset / pwell / attribute / dfield_well / 1 0 0 / le / 2.0 pset / pwell / zone / zone_radius_02.0.zone pset / pwell / attribute / dfield_well / 1 0 0 / le / 4.0 pset / pwell / zone / zone_radius_04.0.zone pset / pwell / attribute / dfield_well / 1 0 0 / le / 8.0 pset / pwell / zone / zone_radius_08.0.zone pset / pwell / attribute / dfield_well / 1 0 0 / le / 16.0 pset / pwell / zone / zone_radius_16.0.zone pset / pwell / attribute / dfield_well / 1 0 0 / le / 32.0 pset / pwell / zone / zone_radius_32.0.zone ```