gel.objective

Definitions, specifications of objectives for inverse optimization

The full functional to be minimized, $\Phi$, is assembled by a matching term $O$ (for "objective") and a regularization term $R$ by $$\Phi=O+\gamma R$$ where $\gamma$ is the (current) regularization parameter.

The specifics are described by str arguments to functions like get_objective_forms and, principally, the object ObjectiveInfo for a more convenient interface.

Objective Functionals $O$

Note that a weight $w(\mathbf{x}_0)$ may be multiplied to the integrands of these options if a u_weight_filename is provided.

"u_metric"

$$\int_{\Omega_{domain}}\|\mathbf{u}_{tar}-\mathbf{u}_{sim}\|_{\ell^2}^2\,d\Omega$$

"c_metric"

$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$

"c_metric_easy_weight"

$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}:\mathbf{C}_{tar}\right)\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$

"c_metric_u_weight"

$$\int_{\Omega_{domain}}\|\mathbf{u}_{tar}\|_{\ell^2}^2\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$

"e_metric"

$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}-\mathbf{I}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}-\mathbf{I}\right)\,d\Omega$$

"inv_metric"

$$\int_{\Omega_{domain}}\left(\mathbf{C}_{sim}^{-1}\mathbf{C}_{tar}-\mathbf{I}\right):\left(\mathbf{C}_{sim}^{-1}\mathbf{C}_{tar}-\mathbf{I}\right)\,d\Omega$$

"rel_metric"

$$\int_{\Omega_{domain}}\text{tr}\left[\mathbf{C}_{sim}\left(\mathbf{C}_{sim}\mathbf{C}_{tar}^{-1}-2\mathbf{I}\right)\mathbf{C}_{tar}^{-1}+\mathbf{I}\right]\,d\Omega$$

"c_bar_metric"

Define a helper tensor $\mathbf{\Xi}$ by

$$\mathbf{\Xi}=\begin{cases} J_{sim}^{-\frac{2}{3}}\mathbf{C}_{sim} - J_{tar}^{-\frac{2}{3}}\mathbf{C}_{tar} & \text{if }J_{tar}>0.5 \newline \mathbf{0} & \text{otherwise} \end{cases}$$

Then, the objective is

$$\int_{\Omega_{domain}}\mathbf{\Xi}:\mathbf{\Xi}\,d\Omega$$

Regularization Functionals $R$

Note that a weight $w(\mathbf{x}_0)$ may be multiplied to the integrands of these options if an u_weight_filename is provided and apply_u_weight_to_reg is enabled.

Without loss of generality as to what modulus representation one is using (see gel.mechanics, i.e. $\alpha$ vs $\beta$), let the control variable be denoted $m$.

"tikhonov"

$$\int_{\Omega_{domain}}\nabla m\cdot\nabla m\,d\Omega$$

"no_regularization"

$$0$$

"tv"

Where $\epsilon$ is a numerical stabilization parameter defined in TV_EPS,

$$\int_{\Omega_{domain}}\sqrt{\nabla m\cdot\nabla m+\epsilon}\,d\Omega$$

"tv_log"

$$\int_{\Omega_{domain}}\frac{\sqrt{\nabla m\cdot\nabla m+\epsilon}}{m}\,d\Omega$$

"tikhonov_h1_metric"

$$\int_{\Omega_{domain}}m^2+\nabla m\cdot\nabla m\,d\Omega$$

"tikhonov_log"

$$\int_{\Omega_{domain}}\frac{\nabla m}{m}\cdot\frac{\nabla m}{m}\,d\Omega$$

"tikhonov_full_h1_log"

$$\int_{\Omega_{domain}}\ln{\left(m\right)}^2+\frac{\nabla m}{m}\cdot\frac{\nabla m}{m}\,d\Omega$$

Domain Specifications $\Omega_{domain}$

"entire_gel"

$\Omega_{domain}$ is the entire hydrogel volume in the underlying gel.geometry.Geometry

Volume within the Event Horizon

This specification is a bit more complicated. The string is prefixed by "exclude_undetectable" in all cases.

When supplied to ObjectiveInfo, get_objective_forms, or validate_objective, then immediately affixed, with no spaces between, follows a str representation of a float. For instance, "exclude_undetectable0.38".

When supplied to get_objective_forms, only the "exclude_undetectable" part is allowed lest an error be thrown. This is because the float inclusion in the latter case is for easy command-line specification of the domain. This get_objective_forms function, however, is called after a gel.geometry.Geometry has already been defined with a specific cutoff defining the Volume within the Event Horizon tag that is used with FEniCS integration.

In any case, this setting uses the Volume within the Event Horizon defined by all hydrogel mesh elements having any adjacent node with displacement meeting or exceeding the provided float threshold in units of microns.

API

  1r"""Definitions, specifications of objectives for inverse optimization
  2
  3The full functional to be minimized, $\Phi$, is assembled by a matching
  4term $O$ (for "objective") and a regularization term $R$ by
  5$$\Phi=O+\gamma R$$
  6where $\gamma$ is the (current) regularization parameter.
  7
  8The specifics are described by str arguments to functions like
  9`get_objective_forms` and, principally, the object `ObjectiveInfo` for
 10a more convenient interface.
 11
 12# Objective Functionals $O$
 13
 14Note that a weight $w(\mathbf{x}_0)$ may be multiplied to the integrands of
 15these options if a `u_weight_filename` is provided.
 16
 17## "u_metric"
 18
 19$$\int_{\Omega_{domain}}\|\mathbf{u}_{tar}-\mathbf{u}_{sim}\|_{\ell^2}^2\,d\Omega$$
 20
 21## "c_metric"
 22
 23$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$
 24
 25## "c_metric_easy_weight"
 26
 27$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}:\mathbf{C}_{tar}\right)\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$
 28
 29## "c_metric_u_weight"
 30
 31$$\int_{\Omega_{domain}}\|\mathbf{u}_{tar}\|_{\ell^2}^2\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}\right)\,d\Omega$$
 32
 33## "e_metric"
 34
 35$$\int_{\Omega_{domain}}\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}-\mathbf{I}\right):\left(\mathbf{C}_{tar}-\mathbf{C}_{sim}-\mathbf{I}\right)\,d\Omega$$
 36
 37## "inv_metric"
 38
 39$$\int_{\Omega_{domain}}\left(\mathbf{C}_{sim}^{-1}\mathbf{C}_{tar}-\mathbf{I}\right):\left(\mathbf{C}_{sim}^{-1}\mathbf{C}_{tar}-\mathbf{I}\right)\,d\Omega$$
 40
 41## "rel_metric"
 42
 43$$\int_{\Omega_{domain}}\text{tr}\left[\mathbf{C}_{sim}\left(\mathbf{C}_{sim}\mathbf{C}_{tar}^{-1}-2\mathbf{I}\right)\mathbf{C}_{tar}^{-1}+\mathbf{I}\right]\,d\Omega$$
 44
 45## "c_bar_metric"
 46
 47Define a helper tensor $\mathbf{\Xi}$ by
 48
 49$$\mathbf{\Xi}=\begin{cases}
 50    J_{sim}^{-\frac{2}{3}}\mathbf{C}_{sim} - J_{tar}^{-\frac{2}{3}}\mathbf{C}_{tar} & \text{if }J_{tar}>0.5 \newline
 51    \mathbf{0} & \text{otherwise}
 52\end{cases}$$
 53
 54Then, the objective is
 55
 56$$\int_{\Omega_{domain}}\mathbf{\Xi}:\mathbf{\Xi}\,d\Omega$$
 57
 58# Regularization Functionals $R$
 59
 60Note that a weight $w(\mathbf{x}_0)$ may be multiplied to the integrands of
 61these options if an `u_weight_filename` is provided
 62**and** `apply_u_weight_to_reg` is enabled.
 63
 64Without loss of generality as to what modulus representation one is
 65using (see `gel.mechanics`, *i.e.* $\alpha$ vs $\beta$), let the control
 66variable be denoted $m$.
 67
 68## "tikhonov"
 69
 70$$\int_{\Omega_{domain}}\nabla m\cdot\nabla m\,d\Omega$$
 71
 72## "no_regularization"
 73
 74$$0$$
 75
 76## "tv"
 77
 78Where $\epsilon$ is a numerical stabilization parameter defined in
 79`TV_EPS`,
 80
 81$$\int_{\Omega_{domain}}\sqrt{\nabla m\cdot\nabla m+\epsilon}\,d\Omega$$
 82
 83## "tv_log"
 84
 85$$\int_{\Omega_{domain}}\frac{\sqrt{\nabla m\cdot\nabla m+\epsilon}}{m}\,d\Omega$$
 86
 87## "tikhonov_h1_metric"
 88
 89$$\int_{\Omega_{domain}}m^2+\nabla m\cdot\nabla m\,d\Omega$$
 90
 91## "tikhonov_log"
 92
 93$$\int_{\Omega_{domain}}\frac{\nabla m}{m}\cdot\frac{\nabla m}{m}\,d\Omega$$
 94
 95## "tikhonov_full_h1_log"
 96
 97$$\int_{\Omega_{domain}}\ln{\left(m\right)}^2+\frac{\nabla m}{m}\cdot\frac{\nabla m}{m}\,d\Omega$$
 98
 99# Domain Specifications $\Omega_{domain}$
100
101## "entire_gel"
102
103$\Omega_{domain}$ is the entire hydrogel volume in the underlying
104`gel.geometry.Geometry`
105
106## Volume within the Event Horizon
107
108This specification is a bit more complicated. The string is *prefixed*
109by "exclude_undetectable" in all cases.
110
111When supplied to `ObjectiveInfo`, `get_objective_forms`, or
112`validate_objective`, then immediately affixed, with no spaces between,
113follows a str representation of a float. For instance,
114"exclude_undetectable0.38".
115
116When supplied to `get_objective_forms`, only the "exclude_undetectable"
117part is allowed lest an error be thrown. This is because the float
118inclusion in the latter case is for easy command-line specification of
119the domain. This `get_objective_forms` function, however, is called
120after a `gel.geometry.Geometry` has already been defined with a
121specific cutoff defining the Volume within the Event Horizon tag that
122is used with FEniCS integration.
123
124In any case, this setting uses the Volume within the Event Horizon
125defined by all hydrogel mesh elements having any adjacent node with
126displacement meeting or exceeding the provided float threshold in units
127of microns.
128
129# API
130"""
131from .header import *
132
133
134_EX_UND = "exclude_undetectable"
135OBJECTIVE_TYPES = [
136    "u_metric",
137    "c_metric",
138    "c_metric_easy_weight",
139    "c_metric_u_weight",
140    "e_metric",
141    "inv_metric",
142    "rel_metric",
143    "c_bar_metric"
144]
145"""list of valid objective functional names"""
146REGULARIZATION_TYPES = [
147    "tikhonov",
148    "no_regularization",
149    "tv",
150    "tv_log",
151    "tikhonov_h1_metric",
152    "tikhonov_log",
153    "tikhonov_full_h1_log"
154]
155"""list of valid regularization functional names"""
156DOMAINS = ["entire_gel", _EX_UND]
157"""list of valid domain *prefixes*"""
158
159TV_EPS=1e-8
160"""Numerical stabilization parameter for total variation regularization"""
161
162
163def validate_objective(
164        objective_type,
165        regularization_type,
166        objective_domain,
167        regularization_domain,
168        u_weight_filename,
169        apply_u_weight_to_reg
170    ):
171    """Determines if the provided arguments can be parsed.
172
173    See `get_objective_forms` for input descriptions.
174
175    Note that both cutoff values must match, if both present.
176
177    Raises: `ValueError` if there is an issue parsing
178    """
179    # Parse domains, check
180    for domain_name, domain in [
181        ("objective", objective_domain),
182        ("regularization", regularization_domain)
183    ]:
184        if domain not in DOMAINS:
185            if domain[:len(_EX_UND)] == _EX_UND:
186                try:
187                    val = float(domain[len(_EX_UND):])
188                except Exception as e:
189                    raise ValueError(
190                        f"{domain_name} domain {objective_domain} improperly "
191                        "suffixed with float string"
192                    )
193            else:
194                raise ValueError(
195                    f"{objective_domain} not a valid {domain_name} domain"
196                )
197    # Check if we get compatible numbers when applicable
198    od_prefix = objective_domain[:len(_EX_UND)]
199    rd_prefix = regularization_domain[:len(_EX_UND)]
200    if od_prefix == _EX_UND and rd_prefix == _EX_UND:
201        if objective_domain != regularization_domain:
202            raise ValueError(
203                "Exclude undetectable domains must be the same at this time, "
204                f"{objective_domain} and {regularization_domain} are not."
205            )
206
207    if objective_type not in OBJECTIVE_TYPES:
208        raise ValueError(f"{objective_type} not a valid objective type")
209    if regularization_type not in REGULARIZATION_TYPES:
210        raise ValueError(
211            f"{regularization_type} not a valid regularization type"
212        )
213
214    # Check have valid file, if requested
215    if u_weight_filename is not None:
216        if not os.path.exists(u_weight_filename):
217            raise ValueError(f"{u_weight_filename} not a valid file")
218
219    if apply_u_weight_to_reg and (u_weight_filename is None):
220        raise ValueError(
221            "Must give a u weight filename to apply to regularization"
222        )
223
224
225def parse_domain(objective_domain, regularization_domain):
226    """Strips float event-horizon cutoff values if applicable
227
228    `objective_domain` and `regularization_domain` as in the arguments
229    to `ObjectiveInfo`
230
231    Returns:
232    * `objective_domain` with cutoff stripped if present
233    * `regularization_domain` with cutoff stripped if present
234    * Event horizon cutoff float if present, otherwise None
235    """
236    detectable_u_cutoff = None
237
238    od_prefix = objective_domain[:len(_EX_UND)]
239    rd_prefix = regularization_domain[:len(_EX_UND)]
240
241    if _EX_UND in [od_prefix, rd_prefix]:
242        # Get the cutoff in microns from the prefix
243        # Validation should ensure cutoffs the same whe matching
244        if od_prefix == _EX_UND:
245            detectable_u_cutoff = float(objective_domain[len(_EX_UND):])
246            # Only keep the name now
247            objective_domain = od_prefix
248        else:
249            detectable_u_cutoff = float(regularization_domain[len(_EX_UND):])
250        if rd_prefix == _EX_UND:
251            # Only keep the name now
252            regularization_domain = rd_prefix
253
254    return objective_domain, regularization_domain, detectable_u_cutoff
255
256
257def get_objective_forms(
258        geo,
259        objective_type,
260        regularization_type,
261        objective_domain,
262        regularization_domain,
263        kinematics_target,
264        kinematics_sim,
265        mod_repr,
266        gamma,
267        logger=None,
268        u_weight_filename=None,
269        apply_u_weight_to_reg=False
270    ):
271    """
272    Returns pre-assembled forms that make up objective.
273
274    * `geo`: `gel.geometry.Geometry` with which integrals are computed
275    * `objective_type`: str specification (see `gel.objective`)
276    * `regularization_type`: str specification (see `gel.objective`)
277    * `objective_domain`: str stripped specification
278    (see `gel.objective`)
279    * `regularization_domain`: str stripped specification
280    (see `gel.objective`)
281    * `kinematics_target`: `gel.kinematics.Kinematics` with tar
282    kinematic quantities involved in objective functional definitions
283    * `kinematics_sim`: `gel.kinematics.Kinematics` with sim kinematic
284    quantities involved in objective functional definitions
285    * `mod_repr`: FEniCS function, denoted $m$ in `gel.objective`, that
286    encodes modulus/the control variable for modulus
287    * `gamma`: float (current) regularization parameter
288    * `logger`: `logging.Logger` instance with which to call `info`
289    functions with information about what is being used
290    * `u_weight_filename`: str path to full-shape .xdmf file with
291    scalar function "w" to be multiplied to integrand in the case
292    where "u_metric" is `objective_type"
293    * `apply_u_weight_to_reg`: bool enables also multiplying above to
294    regularization-term integrand
295
296    Returns:
297    * FEniCS form of entire functional $\Phi$ to be minimized
298    * FEniCS form of the objective/matching term $O$
299    * FEniCS form of the regulariztion term $R$, or None if not using
300    """
301    # Deal with debug output
302    if logger is not None:
303        vprint = logger.info
304    else:
305        vprint = do_nothing_print
306
307    C_target = kinematics_target.C
308    C_sim = kinematics_sim.C
309
310    # Domains
311    if objective_domain == "entire_gel":
312        odx = geo.dx
313        vprint("Using entire gel as pure objective domain.")
314    elif objective_domain == _EX_UND:
315        odx = geo.dx(geo.DETECTABLE_U)
316        vprint("Using detectable u volume as pure objective domain.")
317    else:
318        raise NotImplementedError(
319            f"Don't recognize objective_domain {objective_domain}"
320        )
321
322    if regularization_domain == "entire_gel":
323        rdx = geo.dx
324        vprint("Using entire gel as regularization domain.")
325    elif regularization_domain == _EX_UND:
326        rdx = geo.dx(geo.DETECTABLE_U)
327        vprint("Using detectable u volume as regularization domain.")
328    else:
329        raise NotImplementedError(
330            f"Don't recognize regularization_domain {regularization_domain}"
331        )
332
333    # Pure objective
334    w = None # Sentinel
335    if objective_type == "c_metric":
336        pure_obj_form = inner(C_target-C_sim,C_target-C_sim)*odx
337        vprint("Using C metric as pure objective")
338    elif objective_type == "c_metric_easy_weight":
339        pure_obj_form = (
340            inner(C_target,C_target)
341            * inner(C_target - C_sim, C_target - C_sim)
342            * odx
343        )
344        vprint(r"Using C metric with C_tar:C_tar weight as pure objective")
345    elif objective_type == "c_metric_u_weight":
346        pure_obj_form = (
347            inner(kinematics_target.u, kinematics_target.u)
348            * inner(C_target - C_sim, C_target - C_sim)
349            * odx
350        )
351        vprint(
352            r"Using C metric with weight proportional to |u_tar|^2"
353        )
354    elif objective_type == "e_metric":
355        C_err = C_target - C_sim
356        two_E_err = C_err - Identity(3)
357        pure_obj_form = inner(two_E_err,two_E_err)*odx
358        vprint("Using E metric as pure objective")
359    elif objective_type == "u_metric":
360        u_err = kinematics_target.u - kinematics_sim.u
361        if u_weight_filename is None:
362            pure_obj_form = inner(u_err, u_err)*odx
363        else:
364            vprint("Detected request for u weight from file. Loading...")
365            
366            w = Function(kinematics_target.geo.V0)
367
368            w_file = XDMFFile(u_weight_filename)
369            w_file.read_checkpoint(w, "w", 0)
370
371            w.set_allow_extrapolation(True)
372            w = interpolate(w, kinematics_target.geo.V0)
373
374            vprint("...done loading")
375
376            pure_obj_form = (w*inner(u_err, u_err))*odx
377
378        vprint("Using u metric as pure objective")
379    elif objective_type == "inv_metric":
380        xi_term = (inv(C_sim) * C_target) - Identity(3)
381        pure_obj_form = inner(xi_term, xi_term)*odx
382        vprint("Using inv metric as pure objective")
383    elif objective_type == "rel_metric":
384        inv_C_tar = inv(C_target)
385        id_tensor = Identity(3)
386        integrand = tr(
387            (C_sim*(C_sim*inv_C_tar - 2*id_tensor)*inv_C_tar) + id_tensor
388        )
389        pure_obj_form = integrand*odx
390        vprint("Using rel metric as pure objective")
391    elif objective_type == "c_bar_metric":
392        C_err = conditional(
393            gt(kinematics_target.Ju, 0.5),
394            (
395                (C_sim*kinematics_sim.Ju**(-2/3))
396                - (C_target*kinematics_target.Ju**(-2/3))
397            ),
398            0.0*Identity(3)
399        )
400        pure_obj_form = inner(C_err, C_err)*odx
401        vprint("Using C bar metric as pure objective")
402    else:
403        raise NotImplementedError(
404            f"Don't recognize objective_type {objective_type}"
405        )
406    pre_assembly = pure_obj_form
407
408    # Regularization
409    if regularization_type == "no_regularization":
410        reg_form = None
411        vprint("Not using a regularization with gamma")
412    else:
413        if regularization_type == "tikhonov":
414            ga = grad(mod_repr)
415            reg_form = inner(ga,ga)
416            vprint("Using Tikhonov regularization with H1 seminorm")
417        elif regularization_type == "tv":
418            ga = grad(mod_repr)
419            reg_form = sqrt(inner(ga,ga) + TV_EPS)
420            vprint("Using TV regularization")
421        elif regularization_type == "tv_log":
422            ga = grad(mod_repr)
423            reg_form = sqrt(inner(ga,ga) + TV_EPS)/mod_repr
424            vprint("Using TV regularization of log")
425        elif regularization_type == "tikhonov_h1_metric":
426            ga = grad(mod_repr)
427            reg_form = (
428                mod_repr**2
429                + inner(ga, ga)
430            )
431            vprint("Using Tikhonov regularization with H1 metric")
432        elif regularization_type == "tikhonov_log":
433            gaoa = grad(mod_repr)/mod_repr
434            reg_form = inner(gaoa,gaoa)
435            vprint("Using Tikhonov regularization of log with H1 seminorm")
436        elif regularization_type == "tikhonov_full_h1_log":
437            lna = ln(mod_repr)
438            gaoa = grad(mod_repr)/mod_repr
439            reg_form = (inner(gaoa,gaoa)+(lna**2))
440            vprint("Using Tikhonov regularization of log with full H1")
441        else:
442            raise NotImplementedError(
443                f"Don't recognize regularization_type {regularization_type}"
444            )
445        
446        if apply_u_weight_to_reg:
447            if w is None:
448                raise ValueError(
449                    "Must be using a u weight to apply to regularization"
450                )
451            vprint("Applying u weight to regularization term.")
452            # Weird typing conflicts with multiplication necessitate this
453            reg_form = w * reg_form
454
455        # Weird typing conflicts with multiplication necessitate this
456        reg_form = reg_form * rdx
457
458        pre_assembly += gamma*reg_form
459
460    return pre_assembly, pure_obj_form, reg_form
461
462
463def add_objective_arguments(parser):
464    """Adds entries to `argparse.ArgumentParser` for `ObjectiveInfo`
465
466    * `parser`: `argparse.ArgumentParser` to which command-line
467    arguments are added that will be recognized by `ObjectiveInfo`
468
469    Side-effects: arguments added to `parser`, see `ObjectiveInfo`
470    attributes for specifics
471    """
472    parser.add_argument(
473        "-g",
474        type=float,
475        metavar="GAMMA",
476        default=0.3,
477        help="regularization parameter for this stage"
478    )
479    parser.add_argument(
480        "--u-weight",
481        type=str,
482        metavar="WEIGHT_FILE",
483        default=None,
484        help="filename with spatially-varying weight for matching term"
485    )
486    parser.add_argument(
487        "--apply-u-weight-to-reg",
488        action="store_true",
489        help="applies the weight to the regularization term as well"
490    )
491    parser.add_argument(
492        "--ot",
493        metavar="OBJECTIVE_TYPE",
494        type=str,
495        default="u_metric",
496        help="form of the matching term"
497    )
498    parser.add_argument(
499        "--rt",
500        metavar="REGULARIZATION_TYPE",
501        type=str,
502        default="tikhonov",
503        help="form of the regularization term"
504    )
505    parser.add_argument(
506        "--od",
507        metavar="OBJECTIVE_DOMAIN",
508        type=str,
509        default="exclude_undetectable0.38",
510        help="domain of integral in matching term"
511    )
512    parser.add_argument(
513        "--rd",
514        metavar="REGULARIZATION_DOMAIN",
515        type=str,
516        default="entire_gel",
517        help="domain of integral in regularization term"
518    )
519
520
521class ObjectiveInfo:
522    """Stores objective specification and provides access to functionals"""
523
524    def __init__(self, args):
525        """An object for easy objective description from command line.
526
527        * `args`: `argparse.Namespace` from parsed command-line
528        arguments, specifically those added using `parse_domain`
529        """
530        self.gamma_num = args.g
531        """float regularization parameter from `-g GAMMA`"""
532        self.objective_type = args.ot
533        """str objective specification from `--ot OBJECTIVE_TYPE`"""
534        self.regularization_type = args.rt
535        """str regularization specification from `--rt REGULARIZATION_TYPE`"""
536        self.objective_domain = args.od
537        """str stripped objective domain from `--od OBJECTIVE_DOMAIN`"""
538        self.regularization_domain = args.rd
539        """str stripped regularization domain from
540        `--rd REGULARIZATION_DOMAIN`
541        """
542        self.u_weight_filename = args.u_weight
543        """str filepath from `--u-weight WEIGHT_FILE`"""
544        self.apply_u_weight_to_reg = args.apply_u_weight_to_reg
545        """bool enabled by `--apply-u-weight-to-reg`"""
546
547        validate_objective(
548            self.objective_type,
549            self.regularization_type,
550            self.objective_domain,
551            self.regularization_domain,
552            self.u_weight_filename,
553            self.apply_u_weight_to_reg
554        )
555
556        if self.regularization_type == "no_regularization":
557            self.gamma_num = 0
558
559        # Deal with exclude undetectable case
560        # Only do this now after it is printed and directory is ready
561        parsed = parse_domain(
562            self.objective_domain,
563            self.regularization_domain
564        )
565        self.objective_domain = parsed[0]
566        self.regularization_domain = parsed[1]
567        self.detectable_u_cutoff = parsed[2]
568        """float event horizon cutoff value in microns"""
569
570        self.gamma = Constant(self.gamma_num)
571        """FEniCS Constant with specified $\gamma$ value"""
572
573    def __str__(self):
574        items = [
575            self.gamma_num,
576            self.objective_type,
577            self.regularization_type,
578            self.objective_domain,
579            self.regularization_domain,
580            self.detectable_u_cutoff,
581            self.u_weight_filename,
582            self.apply_u_weight_to_reg
583        ]
584        return ", ".join([str(o) for o in items])
585
586    def __repr__(self):
587        return str(self)
588
589    def log_info(self, logger):
590        """Calls info attribute of `logger` with info on settings."""
591        logger.info(f"Using gamma: {self.gamma_num}")
592        logger.info(f"Using objective type: {self.objective_type}")
593        logger.info(f"Using regularization type: {self.regularization_type}")
594        logger.info(f"Using objective domain: {self.objective_domain}")
595        logger.info(f"Using reg domain: {self.regularization_domain}")
596        logger.info(f"Using detectable cutoff: {self.detectable_u_cutoff}")
597        logger.info(f"Using u_weight_filename: {self.u_weight_filename}")
598        logger.info(f"Applying u weight to reg?: {self.apply_u_weight_to_reg}")
599
600    def safe_u_weight_filename(self):
601        """Returns None if no weight used, else cleansed filename."""
602        if self.u_weight_filename is None:
603            return None
604        return os.path.basename(self.u_weight_filename)
605
606    def get_objective_forms(self, geo, kin_tar, kin_sim, mod_repr, logger):
607        r"""Returns components of the objective functional.
608
609        * `geo`: `gel.geometry.Geometry` with which integrals are
610        computed
611        * `kin_tar`: `gel.kinematics.Kinematics` with target kinematic
612        quantities involved in objective functional definitions
613        * `kin_sim`: `gel.kinematics.Kinematics` with simulated
614        kinematic quantities involved in objective functional
615        definitions
616        * `mod_repr`: FEniCS function, denoted $m$ in `gel.objective`,
617        that encodes modulus/the control variable for modulus
618        * `logger`: `logging.Logger` instance with which to call `info`
619        functions with information about what is being used
620
621        Returns:
622        * FEniCS form of entire functional $\Phi$ to be minimized
623        * FEniCS form of the objective/matching term $O$
624        * FEniCS form of the regulariztion term $R$, or None if not
625        using
626        """
627        pre_assembly, pure_obj_form, reg_form = get_objective_forms(
628            geo,
629            self.objective_type,
630            self.regularization_type,
631            self.objective_domain,
632            self.regularization_domain,
633            kin_tar,
634            kin_sim,
635            mod_repr,
636            self.gamma,
637            logger=logger,
638            u_weight_filename=self.u_weight_filename,
639            apply_u_weight_to_reg=self.apply_u_weight_to_reg
640        )
641        return pre_assembly, pure_obj_form, reg_form
642
643
644def debug_deriv(
645    obj_hat,
646    geo,
647    mod_repr,
648    logger
649):
650    """Uses `info` function in `logger` to print Taylor test results.
651
652    * `obj_hat`: `pyadjoint.ReducedFunctional` object to take derivative
653    of
654    * `geo`: `gel.geometry.Geometry` with appropriate function space
655    to add to current point `mod_repr`
656    * `mod_repr`: point at which to compute derivative, compatible with
657    `obj_hat`
658    * `logger`: something implementing an `info` function to print
659    results
660    """
661    logger.info(f"A Taylor test...")
662
663    h = Function(geo.V0)
664    h.vector()[:] = np.random.rand(h.vector().local_size())
665    taylor_test(obj_hat, mod_repr, h)
666
667    logger.info(f"...completed Taylor test. Expect order 2 convergence.")
OBJECTIVE_TYPES = ['u_metric', 'c_metric', 'c_metric_easy_weight', 'c_metric_u_weight', 'e_metric', 'inv_metric', 'rel_metric', 'c_bar_metric']

list of valid objective functional names

REGULARIZATION_TYPES = ['tikhonov', 'no_regularization', 'tv', 'tv_log', 'tikhonov_h1_metric', 'tikhonov_log', 'tikhonov_full_h1_log']

list of valid regularization functional names

DOMAINS = ['entire_gel', 'exclude_undetectable']

list of valid domain prefixes

TV_EPS = 1e-08

Numerical stabilization parameter for total variation regularization

def validate_objective( objective_type, regularization_type, objective_domain, regularization_domain, u_weight_filename, apply_u_weight_to_reg):
164def validate_objective(
165        objective_type,
166        regularization_type,
167        objective_domain,
168        regularization_domain,
169        u_weight_filename,
170        apply_u_weight_to_reg
171    ):
172    """Determines if the provided arguments can be parsed.
173
174    See `get_objective_forms` for input descriptions.
175
176    Note that both cutoff values must match, if both present.
177
178    Raises: `ValueError` if there is an issue parsing
179    """
180    # Parse domains, check
181    for domain_name, domain in [
182        ("objective", objective_domain),
183        ("regularization", regularization_domain)
184    ]:
185        if domain not in DOMAINS:
186            if domain[:len(_EX_UND)] == _EX_UND:
187                try:
188                    val = float(domain[len(_EX_UND):])
189                except Exception as e:
190                    raise ValueError(
191                        f"{domain_name} domain {objective_domain} improperly "
192                        "suffixed with float string"
193                    )
194            else:
195                raise ValueError(
196                    f"{objective_domain} not a valid {domain_name} domain"
197                )
198    # Check if we get compatible numbers when applicable
199    od_prefix = objective_domain[:len(_EX_UND)]
200    rd_prefix = regularization_domain[:len(_EX_UND)]
201    if od_prefix == _EX_UND and rd_prefix == _EX_UND:
202        if objective_domain != regularization_domain:
203            raise ValueError(
204                "Exclude undetectable domains must be the same at this time, "
205                f"{objective_domain} and {regularization_domain} are not."
206            )
207
208    if objective_type not in OBJECTIVE_TYPES:
209        raise ValueError(f"{objective_type} not a valid objective type")
210    if regularization_type not in REGULARIZATION_TYPES:
211        raise ValueError(
212            f"{regularization_type} not a valid regularization type"
213        )
214
215    # Check have valid file, if requested
216    if u_weight_filename is not None:
217        if not os.path.exists(u_weight_filename):
218            raise ValueError(f"{u_weight_filename} not a valid file")
219
220    if apply_u_weight_to_reg and (u_weight_filename is None):
221        raise ValueError(
222            "Must give a u weight filename to apply to regularization"
223        )

Determines if the provided arguments can be parsed.

See get_objective_forms for input descriptions.

Note that both cutoff values must match, if both present.

Raises: ValueError if there is an issue parsing

def parse_domain(objective_domain, regularization_domain):
226def parse_domain(objective_domain, regularization_domain):
227    """Strips float event-horizon cutoff values if applicable
228
229    `objective_domain` and `regularization_domain` as in the arguments
230    to `ObjectiveInfo`
231
232    Returns:
233    * `objective_domain` with cutoff stripped if present
234    * `regularization_domain` with cutoff stripped if present
235    * Event horizon cutoff float if present, otherwise None
236    """
237    detectable_u_cutoff = None
238
239    od_prefix = objective_domain[:len(_EX_UND)]
240    rd_prefix = regularization_domain[:len(_EX_UND)]
241
242    if _EX_UND in [od_prefix, rd_prefix]:
243        # Get the cutoff in microns from the prefix
244        # Validation should ensure cutoffs the same whe matching
245        if od_prefix == _EX_UND:
246            detectable_u_cutoff = float(objective_domain[len(_EX_UND):])
247            # Only keep the name now
248            objective_domain = od_prefix
249        else:
250            detectable_u_cutoff = float(regularization_domain[len(_EX_UND):])
251        if rd_prefix == _EX_UND:
252            # Only keep the name now
253            regularization_domain = rd_prefix
254
255    return objective_domain, regularization_domain, detectable_u_cutoff

Strips float event-horizon cutoff values if applicable

objective_domain and regularization_domain as in the arguments to ObjectiveInfo

Returns:

  • objective_domain with cutoff stripped if present
  • regularization_domain with cutoff stripped if present
  • Event horizon cutoff float if present, otherwise None
def get_objective_forms( geo, objective_type, regularization_type, objective_domain, regularization_domain, kinematics_target, kinematics_sim, mod_repr, gamma, logger=None, u_weight_filename=None, apply_u_weight_to_reg=False):
258def get_objective_forms(
259        geo,
260        objective_type,
261        regularization_type,
262        objective_domain,
263        regularization_domain,
264        kinematics_target,
265        kinematics_sim,
266        mod_repr,
267        gamma,
268        logger=None,
269        u_weight_filename=None,
270        apply_u_weight_to_reg=False
271    ):
272    """
273    Returns pre-assembled forms that make up objective.
274
275    * `geo`: `gel.geometry.Geometry` with which integrals are computed
276    * `objective_type`: str specification (see `gel.objective`)
277    * `regularization_type`: str specification (see `gel.objective`)
278    * `objective_domain`: str stripped specification
279    (see `gel.objective`)
280    * `regularization_domain`: str stripped specification
281    (see `gel.objective`)
282    * `kinematics_target`: `gel.kinematics.Kinematics` with tar
283    kinematic quantities involved in objective functional definitions
284    * `kinematics_sim`: `gel.kinematics.Kinematics` with sim kinematic
285    quantities involved in objective functional definitions
286    * `mod_repr`: FEniCS function, denoted $m$ in `gel.objective`, that
287    encodes modulus/the control variable for modulus
288    * `gamma`: float (current) regularization parameter
289    * `logger`: `logging.Logger` instance with which to call `info`
290    functions with information about what is being used
291    * `u_weight_filename`: str path to full-shape .xdmf file with
292    scalar function "w" to be multiplied to integrand in the case
293    where "u_metric" is `objective_type"
294    * `apply_u_weight_to_reg`: bool enables also multiplying above to
295    regularization-term integrand
296
297    Returns:
298    * FEniCS form of entire functional $\Phi$ to be minimized
299    * FEniCS form of the objective/matching term $O$
300    * FEniCS form of the regulariztion term $R$, or None if not using
301    """
302    # Deal with debug output
303    if logger is not None:
304        vprint = logger.info
305    else:
306        vprint = do_nothing_print
307
308    C_target = kinematics_target.C
309    C_sim = kinematics_sim.C
310
311    # Domains
312    if objective_domain == "entire_gel":
313        odx = geo.dx
314        vprint("Using entire gel as pure objective domain.")
315    elif objective_domain == _EX_UND:
316        odx = geo.dx(geo.DETECTABLE_U)
317        vprint("Using detectable u volume as pure objective domain.")
318    else:
319        raise NotImplementedError(
320            f"Don't recognize objective_domain {objective_domain}"
321        )
322
323    if regularization_domain == "entire_gel":
324        rdx = geo.dx
325        vprint("Using entire gel as regularization domain.")
326    elif regularization_domain == _EX_UND:
327        rdx = geo.dx(geo.DETECTABLE_U)
328        vprint("Using detectable u volume as regularization domain.")
329    else:
330        raise NotImplementedError(
331            f"Don't recognize regularization_domain {regularization_domain}"
332        )
333
334    # Pure objective
335    w = None # Sentinel
336    if objective_type == "c_metric":
337        pure_obj_form = inner(C_target-C_sim,C_target-C_sim)*odx
338        vprint("Using C metric as pure objective")
339    elif objective_type == "c_metric_easy_weight":
340        pure_obj_form = (
341            inner(C_target,C_target)
342            * inner(C_target - C_sim, C_target - C_sim)
343            * odx
344        )
345        vprint(r"Using C metric with C_tar:C_tar weight as pure objective")
346    elif objective_type == "c_metric_u_weight":
347        pure_obj_form = (
348            inner(kinematics_target.u, kinematics_target.u)
349            * inner(C_target - C_sim, C_target - C_sim)
350            * odx
351        )
352        vprint(
353            r"Using C metric with weight proportional to |u_tar|^2"
354        )
355    elif objective_type == "e_metric":
356        C_err = C_target - C_sim
357        two_E_err = C_err - Identity(3)
358        pure_obj_form = inner(two_E_err,two_E_err)*odx
359        vprint("Using E metric as pure objective")
360    elif objective_type == "u_metric":
361        u_err = kinematics_target.u - kinematics_sim.u
362        if u_weight_filename is None:
363            pure_obj_form = inner(u_err, u_err)*odx
364        else:
365            vprint("Detected request for u weight from file. Loading...")
366            
367            w = Function(kinematics_target.geo.V0)
368
369            w_file = XDMFFile(u_weight_filename)
370            w_file.read_checkpoint(w, "w", 0)
371
372            w.set_allow_extrapolation(True)
373            w = interpolate(w, kinematics_target.geo.V0)
374
375            vprint("...done loading")
376
377            pure_obj_form = (w*inner(u_err, u_err))*odx
378
379        vprint("Using u metric as pure objective")
380    elif objective_type == "inv_metric":
381        xi_term = (inv(C_sim) * C_target) - Identity(3)
382        pure_obj_form = inner(xi_term, xi_term)*odx
383        vprint("Using inv metric as pure objective")
384    elif objective_type == "rel_metric":
385        inv_C_tar = inv(C_target)
386        id_tensor = Identity(3)
387        integrand = tr(
388            (C_sim*(C_sim*inv_C_tar - 2*id_tensor)*inv_C_tar) + id_tensor
389        )
390        pure_obj_form = integrand*odx
391        vprint("Using rel metric as pure objective")
392    elif objective_type == "c_bar_metric":
393        C_err = conditional(
394            gt(kinematics_target.Ju, 0.5),
395            (
396                (C_sim*kinematics_sim.Ju**(-2/3))
397                - (C_target*kinematics_target.Ju**(-2/3))
398            ),
399            0.0*Identity(3)
400        )
401        pure_obj_form = inner(C_err, C_err)*odx
402        vprint("Using C bar metric as pure objective")
403    else:
404        raise NotImplementedError(
405            f"Don't recognize objective_type {objective_type}"
406        )
407    pre_assembly = pure_obj_form
408
409    # Regularization
410    if regularization_type == "no_regularization":
411        reg_form = None
412        vprint("Not using a regularization with gamma")
413    else:
414        if regularization_type == "tikhonov":
415            ga = grad(mod_repr)
416            reg_form = inner(ga,ga)
417            vprint("Using Tikhonov regularization with H1 seminorm")
418        elif regularization_type == "tv":
419            ga = grad(mod_repr)
420            reg_form = sqrt(inner(ga,ga) + TV_EPS)
421            vprint("Using TV regularization")
422        elif regularization_type == "tv_log":
423            ga = grad(mod_repr)
424            reg_form = sqrt(inner(ga,ga) + TV_EPS)/mod_repr
425            vprint("Using TV regularization of log")
426        elif regularization_type == "tikhonov_h1_metric":
427            ga = grad(mod_repr)
428            reg_form = (
429                mod_repr**2
430                + inner(ga, ga)
431            )
432            vprint("Using Tikhonov regularization with H1 metric")
433        elif regularization_type == "tikhonov_log":
434            gaoa = grad(mod_repr)/mod_repr
435            reg_form = inner(gaoa,gaoa)
436            vprint("Using Tikhonov regularization of log with H1 seminorm")
437        elif regularization_type == "tikhonov_full_h1_log":
438            lna = ln(mod_repr)
439            gaoa = grad(mod_repr)/mod_repr
440            reg_form = (inner(gaoa,gaoa)+(lna**2))
441            vprint("Using Tikhonov regularization of log with full H1")
442        else:
443            raise NotImplementedError(
444                f"Don't recognize regularization_type {regularization_type}"
445            )
446        
447        if apply_u_weight_to_reg:
448            if w is None:
449                raise ValueError(
450                    "Must be using a u weight to apply to regularization"
451                )
452            vprint("Applying u weight to regularization term.")
453            # Weird typing conflicts with multiplication necessitate this
454            reg_form = w * reg_form
455
456        # Weird typing conflicts with multiplication necessitate this
457        reg_form = reg_form * rdx
458
459        pre_assembly += gamma*reg_form
460
461    return pre_assembly, pure_obj_form, reg_form

Returns pre-assembled forms that make up objective.

  • geo: gel.geometry.Geometry with which integrals are computed
  • objective_type: str specification (see gel.objective)
  • regularization_type: str specification (see gel.objective)
  • objective_domain: str stripped specification (see gel.objective)
  • regularization_domain: str stripped specification (see gel.objective)
  • kinematics_target: gel.kinematics.Kinematics with tar kinematic quantities involved in objective functional definitions
  • kinematics_sim: gel.kinematics.Kinematics with sim kinematic quantities involved in objective functional definitions
  • mod_repr: FEniCS function, denoted $m$ in gel.objective, that encodes modulus/the control variable for modulus
  • gamma: float (current) regularization parameter
  • logger: logging.Logger instance with which to call info functions with information about what is being used
  • u_weight_filename: str path to full-shape .xdmf file with scalar function "w" to be multiplied to integrand in the case where "u_metric" is `objective_type"
  • apply_u_weight_to_reg: bool enables also multiplying above to regularization-term integrand

Returns:

  • FEniCS form of entire functional $\Phi$ to be minimized
  • FEniCS form of the objective/matching term $O$
  • FEniCS form of the regulariztion term $R$, or None if not using
def add_objective_arguments(parser):
464def add_objective_arguments(parser):
465    """Adds entries to `argparse.ArgumentParser` for `ObjectiveInfo`
466
467    * `parser`: `argparse.ArgumentParser` to which command-line
468    arguments are added that will be recognized by `ObjectiveInfo`
469
470    Side-effects: arguments added to `parser`, see `ObjectiveInfo`
471    attributes for specifics
472    """
473    parser.add_argument(
474        "-g",
475        type=float,
476        metavar="GAMMA",
477        default=0.3,
478        help="regularization parameter for this stage"
479    )
480    parser.add_argument(
481        "--u-weight",
482        type=str,
483        metavar="WEIGHT_FILE",
484        default=None,
485        help="filename with spatially-varying weight for matching term"
486    )
487    parser.add_argument(
488        "--apply-u-weight-to-reg",
489        action="store_true",
490        help="applies the weight to the regularization term as well"
491    )
492    parser.add_argument(
493        "--ot",
494        metavar="OBJECTIVE_TYPE",
495        type=str,
496        default="u_metric",
497        help="form of the matching term"
498    )
499    parser.add_argument(
500        "--rt",
501        metavar="REGULARIZATION_TYPE",
502        type=str,
503        default="tikhonov",
504        help="form of the regularization term"
505    )
506    parser.add_argument(
507        "--od",
508        metavar="OBJECTIVE_DOMAIN",
509        type=str,
510        default="exclude_undetectable0.38",
511        help="domain of integral in matching term"
512    )
513    parser.add_argument(
514        "--rd",
515        metavar="REGULARIZATION_DOMAIN",
516        type=str,
517        default="entire_gel",
518        help="domain of integral in regularization term"
519    )

Adds entries to argparse.ArgumentParser for ObjectiveInfo

  • parser: argparse.ArgumentParser to which command-line arguments are added that will be recognized by ObjectiveInfo

Side-effects: arguments added to parser, see ObjectiveInfo attributes for specifics

class ObjectiveInfo:
522class ObjectiveInfo:
523    """Stores objective specification and provides access to functionals"""
524
525    def __init__(self, args):
526        """An object for easy objective description from command line.
527
528        * `args`: `argparse.Namespace` from parsed command-line
529        arguments, specifically those added using `parse_domain`
530        """
531        self.gamma_num = args.g
532        """float regularization parameter from `-g GAMMA`"""
533        self.objective_type = args.ot
534        """str objective specification from `--ot OBJECTIVE_TYPE`"""
535        self.regularization_type = args.rt
536        """str regularization specification from `--rt REGULARIZATION_TYPE`"""
537        self.objective_domain = args.od
538        """str stripped objective domain from `--od OBJECTIVE_DOMAIN`"""
539        self.regularization_domain = args.rd
540        """str stripped regularization domain from
541        `--rd REGULARIZATION_DOMAIN`
542        """
543        self.u_weight_filename = args.u_weight
544        """str filepath from `--u-weight WEIGHT_FILE`"""
545        self.apply_u_weight_to_reg = args.apply_u_weight_to_reg
546        """bool enabled by `--apply-u-weight-to-reg`"""
547
548        validate_objective(
549            self.objective_type,
550            self.regularization_type,
551            self.objective_domain,
552            self.regularization_domain,
553            self.u_weight_filename,
554            self.apply_u_weight_to_reg
555        )
556
557        if self.regularization_type == "no_regularization":
558            self.gamma_num = 0
559
560        # Deal with exclude undetectable case
561        # Only do this now after it is printed and directory is ready
562        parsed = parse_domain(
563            self.objective_domain,
564            self.regularization_domain
565        )
566        self.objective_domain = parsed[0]
567        self.regularization_domain = parsed[1]
568        self.detectable_u_cutoff = parsed[2]
569        """float event horizon cutoff value in microns"""
570
571        self.gamma = Constant(self.gamma_num)
572        """FEniCS Constant with specified $\gamma$ value"""
573
574    def __str__(self):
575        items = [
576            self.gamma_num,
577            self.objective_type,
578            self.regularization_type,
579            self.objective_domain,
580            self.regularization_domain,
581            self.detectable_u_cutoff,
582            self.u_weight_filename,
583            self.apply_u_weight_to_reg
584        ]
585        return ", ".join([str(o) for o in items])
586
587    def __repr__(self):
588        return str(self)
589
590    def log_info(self, logger):
591        """Calls info attribute of `logger` with info on settings."""
592        logger.info(f"Using gamma: {self.gamma_num}")
593        logger.info(f"Using objective type: {self.objective_type}")
594        logger.info(f"Using regularization type: {self.regularization_type}")
595        logger.info(f"Using objective domain: {self.objective_domain}")
596        logger.info(f"Using reg domain: {self.regularization_domain}")
597        logger.info(f"Using detectable cutoff: {self.detectable_u_cutoff}")
598        logger.info(f"Using u_weight_filename: {self.u_weight_filename}")
599        logger.info(f"Applying u weight to reg?: {self.apply_u_weight_to_reg}")
600
601    def safe_u_weight_filename(self):
602        """Returns None if no weight used, else cleansed filename."""
603        if self.u_weight_filename is None:
604            return None
605        return os.path.basename(self.u_weight_filename)
606
607    def get_objective_forms(self, geo, kin_tar, kin_sim, mod_repr, logger):
608        r"""Returns components of the objective functional.
609
610        * `geo`: `gel.geometry.Geometry` with which integrals are
611        computed
612        * `kin_tar`: `gel.kinematics.Kinematics` with target kinematic
613        quantities involved in objective functional definitions
614        * `kin_sim`: `gel.kinematics.Kinematics` with simulated
615        kinematic quantities involved in objective functional
616        definitions
617        * `mod_repr`: FEniCS function, denoted $m$ in `gel.objective`,
618        that encodes modulus/the control variable for modulus
619        * `logger`: `logging.Logger` instance with which to call `info`
620        functions with information about what is being used
621
622        Returns:
623        * FEniCS form of entire functional $\Phi$ to be minimized
624        * FEniCS form of the objective/matching term $O$
625        * FEniCS form of the regulariztion term $R$, or None if not
626        using
627        """
628        pre_assembly, pure_obj_form, reg_form = get_objective_forms(
629            geo,
630            self.objective_type,
631            self.regularization_type,
632            self.objective_domain,
633            self.regularization_domain,
634            kin_tar,
635            kin_sim,
636            mod_repr,
637            self.gamma,
638            logger=logger,
639            u_weight_filename=self.u_weight_filename,
640            apply_u_weight_to_reg=self.apply_u_weight_to_reg
641        )
642        return pre_assembly, pure_obj_form, reg_form

Stores objective specification and provides access to functionals

ObjectiveInfo(args)
525    def __init__(self, args):
526        """An object for easy objective description from command line.
527
528        * `args`: `argparse.Namespace` from parsed command-line
529        arguments, specifically those added using `parse_domain`
530        """
531        self.gamma_num = args.g
532        """float regularization parameter from `-g GAMMA`"""
533        self.objective_type = args.ot
534        """str objective specification from `--ot OBJECTIVE_TYPE`"""
535        self.regularization_type = args.rt
536        """str regularization specification from `--rt REGULARIZATION_TYPE`"""
537        self.objective_domain = args.od
538        """str stripped objective domain from `--od OBJECTIVE_DOMAIN`"""
539        self.regularization_domain = args.rd
540        """str stripped regularization domain from
541        `--rd REGULARIZATION_DOMAIN`
542        """
543        self.u_weight_filename = args.u_weight
544        """str filepath from `--u-weight WEIGHT_FILE`"""
545        self.apply_u_weight_to_reg = args.apply_u_weight_to_reg
546        """bool enabled by `--apply-u-weight-to-reg`"""
547
548        validate_objective(
549            self.objective_type,
550            self.regularization_type,
551            self.objective_domain,
552            self.regularization_domain,
553            self.u_weight_filename,
554            self.apply_u_weight_to_reg
555        )
556
557        if self.regularization_type == "no_regularization":
558            self.gamma_num = 0
559
560        # Deal with exclude undetectable case
561        # Only do this now after it is printed and directory is ready
562        parsed = parse_domain(
563            self.objective_domain,
564            self.regularization_domain
565        )
566        self.objective_domain = parsed[0]
567        self.regularization_domain = parsed[1]
568        self.detectable_u_cutoff = parsed[2]
569        """float event horizon cutoff value in microns"""
570
571        self.gamma = Constant(self.gamma_num)
572        """FEniCS Constant with specified $\gamma$ value"""

An object for easy objective description from command line.

  • args: argparse.Namespace from parsed command-line arguments, specifically those added using parse_domain
gamma_num

float regularization parameter from -g GAMMA

objective_type

str objective specification from --ot OBJECTIVE_TYPE

regularization_type

str regularization specification from --rt REGULARIZATION_TYPE

objective_domain

str stripped objective domain from --od OBJECTIVE_DOMAIN

regularization_domain

str stripped regularization domain from --rd REGULARIZATION_DOMAIN

u_weight_filename

str filepath from --u-weight WEIGHT_FILE

apply_u_weight_to_reg

bool enabled by --apply-u-weight-to-reg

detectable_u_cutoff

float event horizon cutoff value in microns

gamma

FEniCS Constant with specified $\gamma$ value

def log_info(self, logger):
590    def log_info(self, logger):
591        """Calls info attribute of `logger` with info on settings."""
592        logger.info(f"Using gamma: {self.gamma_num}")
593        logger.info(f"Using objective type: {self.objective_type}")
594        logger.info(f"Using regularization type: {self.regularization_type}")
595        logger.info(f"Using objective domain: {self.objective_domain}")
596        logger.info(f"Using reg domain: {self.regularization_domain}")
597        logger.info(f"Using detectable cutoff: {self.detectable_u_cutoff}")
598        logger.info(f"Using u_weight_filename: {self.u_weight_filename}")
599        logger.info(f"Applying u weight to reg?: {self.apply_u_weight_to_reg}")

Calls info attribute of logger with info on settings.

def safe_u_weight_filename(self):
601    def safe_u_weight_filename(self):
602        """Returns None if no weight used, else cleansed filename."""
603        if self.u_weight_filename is None:
604            return None
605        return os.path.basename(self.u_weight_filename)

Returns None if no weight used, else cleansed filename.

def get_objective_forms(self, geo, kin_tar, kin_sim, mod_repr, logger):
607    def get_objective_forms(self, geo, kin_tar, kin_sim, mod_repr, logger):
608        r"""Returns components of the objective functional.
609
610        * `geo`: `gel.geometry.Geometry` with which integrals are
611        computed
612        * `kin_tar`: `gel.kinematics.Kinematics` with target kinematic
613        quantities involved in objective functional definitions
614        * `kin_sim`: `gel.kinematics.Kinematics` with simulated
615        kinematic quantities involved in objective functional
616        definitions
617        * `mod_repr`: FEniCS function, denoted $m$ in `gel.objective`,
618        that encodes modulus/the control variable for modulus
619        * `logger`: `logging.Logger` instance with which to call `info`
620        functions with information about what is being used
621
622        Returns:
623        * FEniCS form of entire functional $\Phi$ to be minimized
624        * FEniCS form of the objective/matching term $O$
625        * FEniCS form of the regulariztion term $R$, or None if not
626        using
627        """
628        pre_assembly, pure_obj_form, reg_form = get_objective_forms(
629            geo,
630            self.objective_type,
631            self.regularization_type,
632            self.objective_domain,
633            self.regularization_domain,
634            kin_tar,
635            kin_sim,
636            mod_repr,
637            self.gamma,
638            logger=logger,
639            u_weight_filename=self.u_weight_filename,
640            apply_u_weight_to_reg=self.apply_u_weight_to_reg
641        )
642        return pre_assembly, pure_obj_form, reg_form

Returns components of the objective functional.

  • geo: gel.geometry.Geometry with which integrals are computed
  • kin_tar: gel.kinematics.Kinematics with target kinematic quantities involved in objective functional definitions
  • kin_sim: gel.kinematics.Kinematics with simulated kinematic quantities involved in objective functional definitions
  • mod_repr: FEniCS function, denoted $m$ in gel.objective, that encodes modulus/the control variable for modulus
  • logger: logging.Logger instance with which to call info functions with information about what is being used

Returns:

  • FEniCS form of entire functional $\Phi$ to be minimized
  • FEniCS form of the objective/matching term $O$
  • FEniCS form of the regulariztion term $R$, or None if not using
def debug_deriv(obj_hat, geo, mod_repr, logger):
645def debug_deriv(
646    obj_hat,
647    geo,
648    mod_repr,
649    logger
650):
651    """Uses `info` function in `logger` to print Taylor test results.
652
653    * `obj_hat`: `pyadjoint.ReducedFunctional` object to take derivative
654    of
655    * `geo`: `gel.geometry.Geometry` with appropriate function space
656    to add to current point `mod_repr`
657    * `mod_repr`: point at which to compute derivative, compatible with
658    `obj_hat`
659    * `logger`: something implementing an `info` function to print
660    results
661    """
662    logger.info(f"A Taylor test...")
663
664    h = Function(geo.V0)
665    h.vector()[:] = np.random.rand(h.vector().local_size())
666    taylor_test(obj_hat, mod_repr, h)
667
668    logger.info(f"...completed Taylor test. Expect order 2 convergence.")

Uses info function in logger to print Taylor test results.

  • obj_hat: pyadjoint.ReducedFunctional object to take derivative of
  • geo: gel.geometry.Geometry with appropriate function space to add to current point mod_repr
  • mod_repr: point at which to compute derivative, compatible with obj_hat
  • logger: something implementing an info function to print results