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.")
list of valid objective functional names
list of valid regularization functional names
list of valid domain prefixes
Numerical stabilization parameter for total variation regularization
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
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 presentregularization_domain
with cutoff stripped if present- Event horizon cutoff float if present, otherwise None
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 computedobjective_type
: str specification (seegel.objective
)regularization_type
: str specification (seegel.objective
)objective_domain
: str stripped specification (seegel.objective
)regularization_domain
: str stripped specification (seegel.objective
)kinematics_target
:gel.kinematics.Kinematics
with tar kinematic quantities involved in objective functional definitionskinematics_sim
:gel.kinematics.Kinematics
with sim kinematic quantities involved in objective functional definitionsmod_repr
: FEniCS function, denoted $m$ ingel.objective
, that encodes modulus/the control variable for modulusgamma
: float (current) regularization parameterlogger
:logging.Logger
instance with which to callinfo
functions with information about what is being usedu_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
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 byObjectiveInfo
Side-effects: arguments added to parser
, see ObjectiveInfo
attributes for specifics
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
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 usingparse_domain
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.
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.
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 computedkin_tar
:gel.kinematics.Kinematics
with target kinematic quantities involved in objective functional definitionskin_sim
:gel.kinematics.Kinematics
with simulated kinematic quantities involved in objective functional definitionsmod_repr
: FEniCS function, denoted $m$ ingel.objective
, that encodes modulus/the control variable for moduluslogger
:logging.Logger
instance with which to callinfo
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
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 ofgeo
:gel.geometry.Geometry
with appropriate function space to add to current pointmod_repr
mod_repr
: point at which to compute derivative, compatible withobj_hat
logger
: something implementing aninfo
function to print results