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    --u-init U_INIT
 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    parser.add_argument(
116        "--u-init",
117        type=str,
118        metavar="U_INIT",
119        default=None,
120        help="filename of full-shape .xdmf file with initial displacements"
121    )
122
123    return parser
124
125
126@cmp_to_key
127def lexico_sort(coord0, coord1):
128    for i in range(len(coord0)):
129        cmp = coord0[i] - coord1[i]
130        if cmp != 0:
131            return cmp
132    return 0
133
134
135def save_fenics_fcn_nodally(fcn, filename, fcn_name, long_fcn_name=None):
136    """Writes a nodal .xdmf file with given function.
137
138    * `fcn`: FEniCS FE function to write
139    * `filename`: str filename ending in ".xdmf"
140    * `fcn_name`: str short name of the function
141    * `long_fcn_name`: str long name of the function (default same as
142    `fcn_name`)
143
144    Side-effects: writes files `filename` with .xdmf and .h5 endings
145    """
146    output_file = XDMFFile(filename)
147    output_file.parameters["flush_output"] = True
148    output_file.parameters["functions_share_mesh"] = True
149
150    if long_fcn_name is None:
151        long_fcn_name = fcn_name
152
153    fcn.rename(fcn_name, long_fcn_name)
154
155    output_file.write(fcn, 0)
156
157
158def nodal_values_to_meshio(filename):
159    """Reads an .xdmf in "nodal" form to return a `meshio.Mesh` with
160    all point and cell data.
161
162    Note that the `meshio.xdmf.TimeSeriesReader` is involved, but only
163    time 0 is read in accordance with this libraries output style.
164
165    * `filename`: str filename ending in ".xdmf", must be in "nodal"
166    form
167    """
168    # Read in nodal DOFs
169    with meshio.xdmf.TimeSeriesReader(filename) as reader:
170        points, cells = reader.read_points_cells()
171        _, point_data, cell_data = reader.read_data(0)
172
173    return meshio.Mesh(
174        points,
175        cells,
176        point_data=point_data,
177        cell_data=cell_data
178    )
179
180
181def nodal_values_to_fenics_fcn(
182        geo,
183        nodal_values_filename,
184        field_name="mod_repr"
185    ):
186    """Reads a nodal .xdmf file to create a new **scalar** function.
187
188    * `geo`: `gel.geometry.Geometry` with matching hydrogel mesh
189    * `nodal_values_filename`: str filename ending in ".xdmf", must be
190    a "full_shape" form
191    * `field_name`: str the name of the scalar field in the file
192
193    Returns: FEniCS FE scalar function in 1st order Lagrange space
194    """
195    # Read in nodal DOFs
196    mesh = nodal_values_to_meshio(nodal_values_filename)
197    points, cells, point_data, cell_data = \
198        mesh.points, mesh.cells, mesh.point_data, mesh.cell_data
199
200    # Corresponding function space
201    coordinates = geo.V0.tabulate_dof_coordinates()
202
203    # Helper functions
204    sorted_to_meshio = sorted(
205        range(len(points)), key = lambda i : lexico_sort(points[i])
206    )
207    sorted_to_fenics = sorted(
208        range(len(coordinates)), key = lambda i : lexico_sort(coordinates[i])
209    )
210
211    # Into FEniCS order
212    dofs_fenics_order = np.zeros(len(coordinates))
213    dofs_fenics_order[sorted_to_fenics] = \
214            point_data[field_name].flatten()[sorted_to_meshio]
215
216    # Make function
217    fcn = Function(geo.V0)
218    fcn.vector().set_local(dofs_fenics_order)
219    fcn.vector().apply("")
220    fcn.set_allow_extrapolation(True)
221
222    return fcn
223
224
225def save_shape(fcn, filename, fcn_name):
226    """Writes full-shape .xdmf file with given function.
227
228    * `fcn`: FEniCS FE function to write
229    * `filename`: str filename ending in ".xdmf"
230    * `fcn_name`: str short name of the function
231
232    Side-effects: writes files `filename` with .xdmf and .h5 endings
233    """
234    shape_file = XDMFFile(filename)
235    shape_file.parameters["flush_output"] = True
236    shape_file.parameters["functions_share_mesh"] = True
237
238    shape_file.write_checkpoint(
239        fcn,
240        fcn_name,
241        0,
242        XDMFFile.Encoding.HDF5,
243        False
244    )
245
246
247def load_shape(fcn_space, filename, fcn_name):
248    """Reads a full-shape .xdmf file to create a new FEniCS FE function.
249
250    * `fcn_space`: FEniCS FunctionSpace that the function was originally
251    created in
252    * `filename`: str filename ending in ".xdmf", must be in
253    "full_shape" form
254    * `fcn_name`: str the name of the function in the file
255
256    Returns: FEniCS FE function
257    """
258    fcn = Function(fcn_space)
259    shape_file = XDMFFile(filename)
260    shape_file.read_checkpoint(fcn, fcn_name, 0)
261
262    return fcn
def ghrp(data_directory):
31ghrp = lambda data_directory : (
32    lambda fname : os.path.join(data_directory, fname)
33)

Given directory data_directory, return mapping filename to path.

def get_common_parser(*args, **kwargs):
 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    --u-init U_INIT
 54    ```
 55    """
 56    if "formatter_class" not in kwargs:
 57        kwargs["formatter_class"] = argparse.ArgumentDefaultsHelpFormatter
 58
 59    parser = argparse.ArgumentParser(*args, **kwargs)
 60
 61    parser.add_argument(
 62        "-c",
 63        metavar="CELL_DATA_DIR",
 64        default="cell_data",
 65        help="directory containing gel geometry"
 66    )
 67    parser.add_argument(
 68        "-f",
 69        metavar="FORMULATION",
 70        default="beta",
 71        help="form of strain energy density"
 72    )
 73    parser.add_argument(
 74        "-k",
 75        type=float,
 76        metavar="MODULUS_RATIO",
 77        default=1,
 78        help="D1/C1 ratio"
 79    )
 80    parser.add_argument(
 81        "-b",
 82        nargs=2,
 83        type=float,
 84        metavar="BOUNDS",
 85        default=[-2.0, 20.0],
 86        help="bounds for inverse model, or built-in for some formulations"
 87    )
 88    parser.add_argument(
 89        "-l",
 90        type=int,
 91        metavar="LOAD_STEPS",
 92        default=1,
 93        help="forward model BC load step count"
 94    )
 95    parser.add_argument(
 96        "-p",
 97        type=str,
 98        metavar="PRECONDITIONER",
 99        default="hypre_amg",
100        help="preconditioner for forward model Newton-Raphson linear solves"
101    )
102    parser.add_argument(
103        "--bci",
104        type=str,
105        metavar="CELL_SURF_MESH",
106        default=None,
107        help="filename of meshio-compatible mesh with cell surface nodes and u"
108    )
109    parser.add_argument(
110        "--bco",
111        type=str,
112        metavar="OUTER_SURF_MESH",
113        default=None,
114        help="filename of meshio-compatible mesh with outer nodes and u"
115    )
116    parser.add_argument(
117        "--u-init",
118        type=str,
119        metavar="U_INIT",
120        default=None,
121        help="filename of full-shape .xdmf file with initial displacements"
122    )
123
124    return parser

Returns argparse.ArgumentParser equipped with common args.

  • args: positional arguments to argparse.ArgumentParser
  • kwargs: keyword arguments to argparse.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
--u-init U_INIT
def save_fenics_fcn_nodally(fcn, filename, fcn_name, long_fcn_name=None):
136def save_fenics_fcn_nodally(fcn, filename, fcn_name, long_fcn_name=None):
137    """Writes a nodal .xdmf file with given function.
138
139    * `fcn`: FEniCS FE function to write
140    * `filename`: str filename ending in ".xdmf"
141    * `fcn_name`: str short name of the function
142    * `long_fcn_name`: str long name of the function (default same as
143    `fcn_name`)
144
145    Side-effects: writes files `filename` with .xdmf and .h5 endings
146    """
147    output_file = XDMFFile(filename)
148    output_file.parameters["flush_output"] = True
149    output_file.parameters["functions_share_mesh"] = True
150
151    if long_fcn_name is None:
152        long_fcn_name = fcn_name
153
154    fcn.rename(fcn_name, long_fcn_name)
155
156    output_file.write(fcn, 0)

Writes a nodal .xdmf file with given function.

  • fcn: FEniCS FE function to write
  • filename: str filename ending in ".xdmf"
  • fcn_name: str short name of the function
  • long_fcn_name: str long name of the function (default same as fcn_name)

Side-effects: writes files filename with .xdmf and .h5 endings

def nodal_values_to_meshio(filename):
159def nodal_values_to_meshio(filename):
160    """Reads an .xdmf in "nodal" form to return a `meshio.Mesh` with
161    all point and cell data.
162
163    Note that the `meshio.xdmf.TimeSeriesReader` is involved, but only
164    time 0 is read in accordance with this libraries output style.
165
166    * `filename`: str filename ending in ".xdmf", must be in "nodal"
167    form
168    """
169    # Read in nodal DOFs
170    with meshio.xdmf.TimeSeriesReader(filename) as reader:
171        points, cells = reader.read_points_cells()
172        _, point_data, cell_data = reader.read_data(0)
173
174    return meshio.Mesh(
175        points,
176        cells,
177        point_data=point_data,
178        cell_data=cell_data
179    )

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
def nodal_values_to_fenics_fcn(geo, nodal_values_filename, field_name='mod_repr'):
182def nodal_values_to_fenics_fcn(
183        geo,
184        nodal_values_filename,
185        field_name="mod_repr"
186    ):
187    """Reads a nodal .xdmf file to create a new **scalar** function.
188
189    * `geo`: `gel.geometry.Geometry` with matching hydrogel mesh
190    * `nodal_values_filename`: str filename ending in ".xdmf", must be
191    a "full_shape" form
192    * `field_name`: str the name of the scalar field in the file
193
194    Returns: FEniCS FE scalar function in 1st order Lagrange space
195    """
196    # Read in nodal DOFs
197    mesh = nodal_values_to_meshio(nodal_values_filename)
198    points, cells, point_data, cell_data = \
199        mesh.points, mesh.cells, mesh.point_data, mesh.cell_data
200
201    # Corresponding function space
202    coordinates = geo.V0.tabulate_dof_coordinates()
203
204    # Helper functions
205    sorted_to_meshio = sorted(
206        range(len(points)), key = lambda i : lexico_sort(points[i])
207    )
208    sorted_to_fenics = sorted(
209        range(len(coordinates)), key = lambda i : lexico_sort(coordinates[i])
210    )
211
212    # Into FEniCS order
213    dofs_fenics_order = np.zeros(len(coordinates))
214    dofs_fenics_order[sorted_to_fenics] = \
215            point_data[field_name].flatten()[sorted_to_meshio]
216
217    # Make function
218    fcn = Function(geo.V0)
219    fcn.vector().set_local(dofs_fenics_order)
220    fcn.vector().apply("")
221    fcn.set_allow_extrapolation(True)
222
223    return fcn

Reads a nodal .xdmf file to create a new scalar function.

  • geo: gel.geometry.Geometry with matching hydrogel mesh
  • nodal_values_filename: str filename ending in ".xdmf", must be a "full_shape" form
  • field_name: str the name of the scalar field in the file

Returns: FEniCS FE scalar function in 1st order Lagrange space

def save_shape(fcn, filename, fcn_name):
226def save_shape(fcn, filename, fcn_name):
227    """Writes full-shape .xdmf file with given function.
228
229    * `fcn`: FEniCS FE function to write
230    * `filename`: str filename ending in ".xdmf"
231    * `fcn_name`: str short name of the function
232
233    Side-effects: writes files `filename` with .xdmf and .h5 endings
234    """
235    shape_file = XDMFFile(filename)
236    shape_file.parameters["flush_output"] = True
237    shape_file.parameters["functions_share_mesh"] = True
238
239    shape_file.write_checkpoint(
240        fcn,
241        fcn_name,
242        0,
243        XDMFFile.Encoding.HDF5,
244        False
245    )

Writes full-shape .xdmf file with given function.

  • fcn: FEniCS FE function to write
  • filename: str filename ending in ".xdmf"
  • fcn_name: str short name of the function

Side-effects: writes files filename with .xdmf and .h5 endings

def load_shape(fcn_space, filename, fcn_name):
248def load_shape(fcn_space, filename, fcn_name):
249    """Reads a full-shape .xdmf file to create a new FEniCS FE function.
250
251    * `fcn_space`: FEniCS FunctionSpace that the function was originally
252    created in
253    * `filename`: str filename ending in ".xdmf", must be in
254    "full_shape" form
255    * `fcn_name`: str the name of the function in the file
256
257    Returns: FEniCS FE function
258    """
259    fcn = Function(fcn_space)
260    shape_file = XDMFFile(filename)
261    shape_file.read_checkpoint(fcn, fcn_name, 0)
262
263    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 in
  • filename: str filename ending in ".xdmf", must be in "full_shape" form
  • fcn_name: str the name of the function in the file

Returns: FEniCS FE function