7
7
8
8
from abc import ABC
9
9
from functools import partial
10
+ from typing import Callable
10
11
11
12
import numpy as np
12
13
16
17
class BaseMetric (ABC ):
17
18
"""Base class for a metric on algebraic variant of mixed-dimensional variables."""
18
19
19
- def variable_norm (self , solution : np .ndarray ) -> float :
20
+ def variable_norm (self , values : np .ndarray ) -> float :
20
21
"""Base method for measuring the size of physical states (increments, solution etc.)
21
22
22
23
Parameters:
23
- solution : algebraic respresentation of a mixed-dimensional variable
24
+ values : algebraic respresentation of a mixed-dimensional variable
24
25
25
26
Returns:
26
- float: measure of solution
27
+ float: measure of values
27
28
28
29
"""
29
30
raise NotImplementedError ("This is an abstract class." )
@@ -36,67 +37,64 @@ class EuclideanMetric(BaseMetric):
36
37
e.g. considering errors for each variable and/or each grid separately,
37
38
possibly using _l2_norm_cell
38
39
39
- We normalize by the size of the solution vector as proxy for domain size.
40
+ We normalize by the size of the vector as proxy for domain size.
40
41
41
42
"""
42
43
43
- def variable_norm (self , solution : np .ndarray ) -> float :
44
+ def variable_norm (self , values : np .ndarray ) -> float :
44
45
"""Implementation of Euclidean l2 norm of the full vector, scaled by vector size.
45
46
46
47
Parameters:
47
- solution : algebraic respresentation of a mixed-dimensional variable
48
+ values : algebraic respresentation of a mixed-dimensional variable
48
49
49
50
Returns:
50
- float: measure of solution
51
+ float: measure of values
51
52
52
53
"""
53
- return np .linalg .norm (solution ) / np .sqrt (solution .size )
54
+ return np .linalg .norm (values ) / np .sqrt (values .size )
54
55
55
56
56
57
class LebesgueMetric (BaseMetric ):
57
58
"""Dimension-consistent Lebesgue metric (blind to physics), but separates dimensions."""
58
59
59
- def variable_norm (self , solution : np .ndarray ) -> float :
60
- """Implementation of Lebesgue L2 norm of the physical solution.
60
+ equation_system : pp .EquationSystem
61
+ """EquationSystem object for the current model. Normally defined in a mixin class
62
+ defining the solution strategy.
63
+
64
+ """
65
+ volume_integral : Callable [[pp .ad .Operator , list [pp .Grid ], int ], pp .ad .Operator ]
66
+ """General volume integral operator, defined in `pp.BalanceEquation`."""
67
+
68
+ def variable_norm (self , values : np .ndarray ) -> float :
69
+ """Implementation of mixed-dimensional Lebesgue L2 norm of a physical state.
61
70
62
71
Parameters:
63
- solution : algebraic respresentation of a mixed-dimensional variable
72
+ values : algebraic respresentation of a mixed-dimensional variable
64
73
65
74
Returns:
66
- float: measure of solution
75
+ float: measure of values
67
76
68
77
"""
69
78
# Initialize container for collecting separate L2 norms (squarred).
70
79
integrals_squarred = []
71
80
72
- # Convert algebraic solution vector to mixed dimensional variable
73
- # TODO - The current implementation utilizes the datastructures in place, which is
74
- # not very elegant...the creation of a isolated MixedDimensionalVariable without
75
- # data transfer would be better.
76
- cached_variable_values = self .equation_system .get_variable_values (
77
- iterate_index = 0
78
- )
79
- self .equation_system .set_variable_values (solution , iterate_index = 0 )
80
-
81
- # Treat each variable separately - with this separate also dimensions
81
+ # Use the equation system to get a view onto mixed-dimensional data structures.
82
+ # Compute the L2 norm of each variable separately, automatically taking into
83
+ # account volume and specific volume
82
84
for variable in self .equation_system .variables :
83
85
84
- # Compute square of the L2 norm taking into account volume and specific volume
85
86
l2_norm = pp .ad .Function (partial (pp .ad .l2_norm , variable .dim ), "l2_norm" )
86
87
sd = variable .domain
88
+ indices = self .equation_system .dofs_of (variable )
89
+ ad_values = pp .ad .DenseArray (values [indices ])
87
90
integral_squarred = np .sum (
88
- self .volume_integral (l2_norm (variable ) ** 2 , [sd ], dim = 1 ).value (
91
+ self .volume_integral (l2_norm (ad_values ) ** 2 , [sd ], 1 ).value (
89
92
self .equation_system
90
93
)
91
94
)
92
95
93
96
# Collect the L2 norm squared.
94
97
integrals_squarred .append (integral_squarred )
95
98
96
- # Reset the cached variable values
97
- self .equation_system .set_variable_values (
98
- cached_variable_values , iterate_index = 0
99
- )
100
-
101
99
# Squash all results by employing a consistent L2 approach.
102
100
return np .sqrt (np .sum (integrals_squarred ))
0 commit comments