gel.helper
A variety of helper functions.
Notably, includes functions for generalized reading and writing from mesh files. This is necessary due to the variety of interfaces that may be easiest to work with, given a task.
A meshio.Mesh
object is useful for extracting point/cell data
according to the event horizon mesh output from gel.scripts.get_veh
.
nodal_values_to_meshio
achieves this task.
"Full-shape" .xdmf files are created from write_checkpoint methods, and
are suitable for reading and writing directly in and out of FEniCS
without additional machinery necessary. Associated functions include
save_shape
and load_shape
.
"Nodal" .xdmf files are best for post-processing with Paraview as they
have a compatible embedding of connectivity information and are smaller
files. However, some floating-point precision loss has been observed.
Associated functions for working with function DoFs in this manner
include save_fenics_fcn_nodally
and nodal_values_to_fenics_fcn
.
API
1"""A variety of helper functions. 2 3Notably, includes functions for generalized reading and writing from 4mesh files. This is necessary due to the variety of interfaces that 5may be easiest to work with, given a task. 6 7A `meshio.Mesh` object is useful for extracting point/cell data 8according to the event horizon mesh output from `gel.scripts.get_veh`. 9`nodal_values_to_meshio` achieves this task. 10 11"Full-shape" .xdmf files are created from write_checkpoint methods, and 12are suitable for reading and writing directly in and out of FEniCS 13without additional machinery necessary. Associated functions include 14`save_shape` and `load_shape`. 15 16"Nodal" .xdmf files are best for post-processing with Paraview as they 17have a compatible embedding of connectivity information and are smaller 18files. However, some floating-point precision loss has been observed. 19Associated functions for working with function DoFs in this manner 20include `save_fenics_fcn_nodally` and `nodal_values_to_fenics_fcn`. 21 22# API 23""" 24from .header import * 25import os 26import argparse 27from functools import cmp_to_key 28 29 30ghrp = lambda data_directory : ( 31 lambda fname : os.path.join(data_directory, fname) 32) 33"""Given directory `data_directory`, return mapping filename to path.""" 34 35 36def get_common_parser(*args, **kwargs): 37 """Returns `argparse.ArgumentParser` equipped with common args. 38 39 * `args`: positional arguments to `argparse.ArgumentParser` 40 * `kwargs`: keyword arguments to `argparse.ArgumentParser` 41 42 Included arguments: 43 ``` 44 -c CELL_DATA_DIR 45 -f FORMULATION 46 -k MODULUS_RATIO 47 -b BOUNDS 48 -l LOAD_STEPS 49 -p PRECONDITIONER 50 --bci CELL_SURF_MESH 51 --bco OUTER_SURF_MESH 52 ``` 53 """ 54 if "formatter_class" not in kwargs: 55 kwargs["formatter_class"] = argparse.ArgumentDefaultsHelpFormatter 56 57 parser = argparse.ArgumentParser(*args, **kwargs) 58 59 parser.add_argument( 60 "-c", 61 metavar="CELL_DATA_DIR", 62 default="cell_data", 63 help="directory containing gel geometry" 64 ) 65 parser.add_argument( 66 "-f", 67 metavar="FORMULATION", 68 default="beta", 69 help="form of strain energy density" 70 ) 71 parser.add_argument( 72 "-k", 73 type=float, 74 metavar="MODULUS_RATIO", 75 default=1, 76 help="D1/C1 ratio" 77 ) 78 parser.add_argument( 79 "-b", 80 nargs=2, 81 type=float, 82 metavar="BOUNDS", 83 default=[-2.0, 20.0], 84 help="bounds for inverse model, or built-in for some formulations" 85 ) 86 parser.add_argument( 87 "-l", 88 type=int, 89 metavar="LOAD_STEPS", 90 default=1, 91 help="forward model BC load step count" 92 ) 93 parser.add_argument( 94 "-p", 95 type=str, 96 metavar="PRECONDITIONER", 97 default="hypre_amg", 98 help="preconditioner for forward model Newton-Raphson linear solves" 99 ) 100 parser.add_argument( 101 "--bci", 102 type=str, 103 metavar="CELL_SURF_MESH", 104 default=None, 105 help="filename of meshio-compatible mesh with cell surface nodes and u" 106 ) 107 parser.add_argument( 108 "--bco", 109 type=str, 110 metavar="OUTER_SURF_MESH", 111 default=None, 112 help="filename of meshio-compatible mesh with outer nodes and u" 113 ) 114 115 return parser 116 117 118@cmp_to_key 119def lexico_sort(coord0, coord1): 120 for i in range(len(coord0)): 121 cmp = coord0[i] - coord1[i] 122 if cmp != 0: 123 return cmp 124 return 0 125 126 127def save_fenics_fcn_nodally(fcn, filename, fcn_name, long_fcn_name=None): 128 """Writes a nodal .xdmf file with given function. 129 130 * `fcn`: FEniCS FE function to write 131 * `filename`: str filename ending in ".xdmf" 132 * `fcn_name`: str short name of the function 133 * `long_fcn_name`: str long name of the function (default same as 134 `fcn_name`) 135 136 Side-effects: writes files `filename` with .xdmf and .h5 endings 137 """ 138 output_file = XDMFFile(filename) 139 output_file.parameters["flush_output"] = True 140 output_file.parameters["functions_share_mesh"] = True 141 142 if long_fcn_name is None: 143 long_fcn_name = fcn_name 144 145 fcn.rename(fcn_name, long_fcn_name) 146 147 output_file.write(fcn, 0) 148 149 150def nodal_values_to_meshio(filename): 151 """Reads an .xdmf in "nodal" form to return a `meshio.Mesh` with 152 all point and cell data. 153 154 Note that the `meshio.xdmf.TimeSeriesReader` is involved, but only 155 time 0 is read in accordance with this libraries output style. 156 157 * `filename`: str filename ending in ".xdmf", must be in "nodal" 158 form 159 """ 160 # Read in nodal DOFs 161 with meshio.xdmf.TimeSeriesReader(filename) as reader: 162 points, cells = reader.read_points_cells() 163 _, point_data, cell_data = reader.read_data(0) 164 165 return meshio.Mesh( 166 points, 167 cells, 168 point_data=point_data, 169 cell_data=cell_data 170 ) 171 172 173def nodal_values_to_fenics_fcn( 174 geo, 175 nodal_values_filename, 176 field_name="mod_repr" 177 ): 178 """Reads a nodal .xdmf file to create a new **scalar** function. 179 180 * `geo`: `gel.geometry.Geometry` with matching hydrogel mesh 181 * `nodal_values_filename`: str filename ending in ".xdmf", must be 182 a "full_shape" form 183 * `field_name`: str the name of the scalar field in the file 184 185 Returns: FEniCS FE scalar function in 1st order Lagrange space 186 """ 187 # Read in nodal DOFs 188 mesh = nodal_values_to_meshio(nodal_values_filename) 189 points, cells, point_data, cell_data = \ 190 mesh.points, mesh.cells, mesh.point_data, mesh.cell_data 191 192 # Corresponding function space 193 coordinates = geo.V0.tabulate_dof_coordinates() 194 195 # Helper functions 196 sorted_to_meshio = sorted( 197 range(len(points)), key = lambda i : lexico_sort(points[i]) 198 ) 199 sorted_to_fenics = sorted( 200 range(len(coordinates)), key = lambda i : lexico_sort(coordinates[i]) 201 ) 202 203 # Into FEniCS order 204 dofs_fenics_order = np.zeros(len(coordinates)) 205 dofs_fenics_order[sorted_to_fenics] = \ 206 point_data[field_name].flatten()[sorted_to_meshio] 207 208 # Make function 209 fcn = Function(geo.V0) 210 fcn.vector().set_local(dofs_fenics_order) 211 fcn.vector().apply("") 212 fcn.set_allow_extrapolation(True) 213 214 return fcn 215 216 217def save_shape(fcn, filename, fcn_name): 218 """Writes full-shape .xdmf file with given function. 219 220 * `fcn`: FEniCS FE function to write 221 * `filename`: str filename ending in ".xdmf" 222 * `fcn_name`: str short name of the function 223 224 Side-effects: writes files `filename` with .xdmf and .h5 endings 225 """ 226 shape_file = XDMFFile(filename) 227 shape_file.parameters["flush_output"] = True 228 shape_file.parameters["functions_share_mesh"] = True 229 230 shape_file.write_checkpoint( 231 fcn, 232 fcn_name, 233 0, 234 XDMFFile.Encoding.HDF5, 235 False 236 ) 237 238 239def load_shape(fcn_space, filename, fcn_name): 240 """Reads a full-shape .xdmf file to create a new FEniCS FE function. 241 242 * `fcn_space`: FEniCS FunctionSpace that the function was originally 243 created in 244 * `filename`: str filename ending in ".xdmf", must be in 245 "full_shape" form 246 * `fcn_name`: str the name of the function in the file 247 248 Returns: FEniCS FE function 249 """ 250 fcn = Function(fcn_space) 251 shape_file = XDMFFile(filename) 252 shape_file.read_checkpoint(fcn, fcn_name, 0) 253 254 return fcn
Given directory data_directory
, return mapping filename to path.
37def get_common_parser(*args, **kwargs): 38 """Returns `argparse.ArgumentParser` equipped with common args. 39 40 * `args`: positional arguments to `argparse.ArgumentParser` 41 * `kwargs`: keyword arguments to `argparse.ArgumentParser` 42 43 Included arguments: 44 ``` 45 -c CELL_DATA_DIR 46 -f FORMULATION 47 -k MODULUS_RATIO 48 -b BOUNDS 49 -l LOAD_STEPS 50 -p PRECONDITIONER 51 --bci CELL_SURF_MESH 52 --bco OUTER_SURF_MESH 53 ``` 54 """ 55 if "formatter_class" not in kwargs: 56 kwargs["formatter_class"] = argparse.ArgumentDefaultsHelpFormatter 57 58 parser = argparse.ArgumentParser(*args, **kwargs) 59 60 parser.add_argument( 61 "-c", 62 metavar="CELL_DATA_DIR", 63 default="cell_data", 64 help="directory containing gel geometry" 65 ) 66 parser.add_argument( 67 "-f", 68 metavar="FORMULATION", 69 default="beta", 70 help="form of strain energy density" 71 ) 72 parser.add_argument( 73 "-k", 74 type=float, 75 metavar="MODULUS_RATIO", 76 default=1, 77 help="D1/C1 ratio" 78 ) 79 parser.add_argument( 80 "-b", 81 nargs=2, 82 type=float, 83 metavar="BOUNDS", 84 default=[-2.0, 20.0], 85 help="bounds for inverse model, or built-in for some formulations" 86 ) 87 parser.add_argument( 88 "-l", 89 type=int, 90 metavar="LOAD_STEPS", 91 default=1, 92 help="forward model BC load step count" 93 ) 94 parser.add_argument( 95 "-p", 96 type=str, 97 metavar="PRECONDITIONER", 98 default="hypre_amg", 99 help="preconditioner for forward model Newton-Raphson linear solves" 100 ) 101 parser.add_argument( 102 "--bci", 103 type=str, 104 metavar="CELL_SURF_MESH", 105 default=None, 106 help="filename of meshio-compatible mesh with cell surface nodes and u" 107 ) 108 parser.add_argument( 109 "--bco", 110 type=str, 111 metavar="OUTER_SURF_MESH", 112 default=None, 113 help="filename of meshio-compatible mesh with outer nodes and u" 114 ) 115 116 return parser
Returns argparse.ArgumentParser
equipped with common args.
args
: positional arguments toargparse.ArgumentParser
kwargs
: keyword arguments toargparse.ArgumentParser
Included arguments:
-c CELL_DATA_DIR
-f FORMULATION
-k MODULUS_RATIO
-b BOUNDS
-l LOAD_STEPS
-p PRECONDITIONER
--bci CELL_SURF_MESH
--bco OUTER_SURF_MESH
128def save_fenics_fcn_nodally(fcn, filename, fcn_name, long_fcn_name=None): 129 """Writes a nodal .xdmf file with given function. 130 131 * `fcn`: FEniCS FE function to write 132 * `filename`: str filename ending in ".xdmf" 133 * `fcn_name`: str short name of the function 134 * `long_fcn_name`: str long name of the function (default same as 135 `fcn_name`) 136 137 Side-effects: writes files `filename` with .xdmf and .h5 endings 138 """ 139 output_file = XDMFFile(filename) 140 output_file.parameters["flush_output"] = True 141 output_file.parameters["functions_share_mesh"] = True 142 143 if long_fcn_name is None: 144 long_fcn_name = fcn_name 145 146 fcn.rename(fcn_name, long_fcn_name) 147 148 output_file.write(fcn, 0)
Writes a nodal .xdmf file with given function.
fcn
: FEniCS FE function to writefilename
: str filename ending in ".xdmf"fcn_name
: str short name of the functionlong_fcn_name
: str long name of the function (default same asfcn_name
)
Side-effects: writes files filename
with .xdmf and .h5 endings
151def nodal_values_to_meshio(filename): 152 """Reads an .xdmf in "nodal" form to return a `meshio.Mesh` with 153 all point and cell data. 154 155 Note that the `meshio.xdmf.TimeSeriesReader` is involved, but only 156 time 0 is read in accordance with this libraries output style. 157 158 * `filename`: str filename ending in ".xdmf", must be in "nodal" 159 form 160 """ 161 # Read in nodal DOFs 162 with meshio.xdmf.TimeSeriesReader(filename) as reader: 163 points, cells = reader.read_points_cells() 164 _, point_data, cell_data = reader.read_data(0) 165 166 return meshio.Mesh( 167 points, 168 cells, 169 point_data=point_data, 170 cell_data=cell_data 171 )
Reads an .xdmf in "nodal" form to return a meshio.Mesh
with
all point and cell data.
Note that the meshio.xdmf.TimeSeriesReader
is involved, but only
time 0 is read in accordance with this libraries output style.
filename
: str filename ending in ".xdmf", must be in "nodal" form
174def nodal_values_to_fenics_fcn( 175 geo, 176 nodal_values_filename, 177 field_name="mod_repr" 178 ): 179 """Reads a nodal .xdmf file to create a new **scalar** function. 180 181 * `geo`: `gel.geometry.Geometry` with matching hydrogel mesh 182 * `nodal_values_filename`: str filename ending in ".xdmf", must be 183 a "full_shape" form 184 * `field_name`: str the name of the scalar field in the file 185 186 Returns: FEniCS FE scalar function in 1st order Lagrange space 187 """ 188 # Read in nodal DOFs 189 mesh = nodal_values_to_meshio(nodal_values_filename) 190 points, cells, point_data, cell_data = \ 191 mesh.points, mesh.cells, mesh.point_data, mesh.cell_data 192 193 # Corresponding function space 194 coordinates = geo.V0.tabulate_dof_coordinates() 195 196 # Helper functions 197 sorted_to_meshio = sorted( 198 range(len(points)), key = lambda i : lexico_sort(points[i]) 199 ) 200 sorted_to_fenics = sorted( 201 range(len(coordinates)), key = lambda i : lexico_sort(coordinates[i]) 202 ) 203 204 # Into FEniCS order 205 dofs_fenics_order = np.zeros(len(coordinates)) 206 dofs_fenics_order[sorted_to_fenics] = \ 207 point_data[field_name].flatten()[sorted_to_meshio] 208 209 # Make function 210 fcn = Function(geo.V0) 211 fcn.vector().set_local(dofs_fenics_order) 212 fcn.vector().apply("") 213 fcn.set_allow_extrapolation(True) 214 215 return fcn
Reads a nodal .xdmf file to create a new scalar function.
geo
:gel.geometry.Geometry
with matching hydrogel meshnodal_values_filename
: str filename ending in ".xdmf", must be a "full_shape" formfield_name
: str the name of the scalar field in the file
Returns: FEniCS FE scalar function in 1st order Lagrange space
218def save_shape(fcn, filename, fcn_name): 219 """Writes full-shape .xdmf file with given function. 220 221 * `fcn`: FEniCS FE function to write 222 * `filename`: str filename ending in ".xdmf" 223 * `fcn_name`: str short name of the function 224 225 Side-effects: writes files `filename` with .xdmf and .h5 endings 226 """ 227 shape_file = XDMFFile(filename) 228 shape_file.parameters["flush_output"] = True 229 shape_file.parameters["functions_share_mesh"] = True 230 231 shape_file.write_checkpoint( 232 fcn, 233 fcn_name, 234 0, 235 XDMFFile.Encoding.HDF5, 236 False 237 )
Writes full-shape .xdmf file with given function.
fcn
: FEniCS FE function to writefilename
: str filename ending in ".xdmf"fcn_name
: str short name of the function
Side-effects: writes files filename
with .xdmf and .h5 endings
240def load_shape(fcn_space, filename, fcn_name): 241 """Reads a full-shape .xdmf file to create a new FEniCS FE function. 242 243 * `fcn_space`: FEniCS FunctionSpace that the function was originally 244 created in 245 * `filename`: str filename ending in ".xdmf", must be in 246 "full_shape" form 247 * `fcn_name`: str the name of the function in the file 248 249 Returns: FEniCS FE function 250 """ 251 fcn = Function(fcn_space) 252 shape_file = XDMFFile(filename) 253 shape_file.read_checkpoint(fcn, fcn_name, 0) 254 255 return fcn
Reads a full-shape .xdmf file to create a new FEniCS FE function.
fcn_space
: FEniCS FunctionSpace that the function was originally created infilename
: str filename ending in ".xdmf", must be in "full_shape" formfcn_name
: str the name of the function in the file
Returns: FEniCS FE function