• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

TRI-AMDD / mpet / 8476080312

29 Mar 2024 01:46AM UTC coverage: 55.461% (-7.2%) from 62.648%
8476080312

Pull #126

github

d-cogswell
Adds a benchmark section to docs.
Pull Request #126: v1.0.0

2351 of 4239 relevant lines covered (55.46%)

2.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.96
/mpet/config/derived_values.py
1
import numpy as np
4✔
2

3
from mpet import props_am
4✔
4
from mpet.exceptions import UnknownParameterError
4✔
5
from mpet.config import constants
4✔
6
from mpet.utils import import_function
4✔
7

8

9
class DerivedValues:
4✔
10
    def __init__(self):
4✔
11
        """
12
        DerivedValues holds the functions and equations required
13
        to calculate a parameter that is derived from other parameters.
14
        Results are cached, so each parameter is calculated only once.
15
        This class is meant to be used from within :class:`mpet.config.configuration.Config`.
16

17
        Like :class:`mpet.config.configuration.Config`, the ``[]`` operator
18
        can be used to access values.
19

20
        Each method of this class that does not start with an underscore
21
        is a derived value that can be calculated. If it has a ``trode``
22
        argument, the parameter is electrode-specific and the name
23
        of the electrode should be specified (either 'a' or 'c').
24

25
        A list of the available parameters is stored in ``self.available_values``.
26

27
        Where applicable, all parameters are scaled to their non-dimensional values.
28

29
        .. make sure to document methods related to [] operator
30
        .. automethod:: __getitem__
31
        """
32
        # to keep track of values that were already calculated
33
        # initialize with empty dicts for electrodes
34
        self.values = {'c': {}, 'a': {}}
4✔
35

36
        # placeholder for config
37
        self.config = None
4✔
38

39
        # store list of available derived values: any method of which
40
        # the name does not start with _
41
        # callable is a trick to avoid returning attributes like self.config as well
42
        self.available_values = [k for k in dir(self) if not k.startswith('_')
4✔
43
                                 and callable(getattr(self, k))]
44

45
    def __repr__(self):
4✔
46
        """
47
        Representation when printing this class:
48
        print the underlying dict with parameter values
49
        """
50
        return dict.__repr__(self.values)
×
51

52
    def __getitem__(self, args):
4✔
53
        """
54
        Retrieve a derived parameter using the ``[]`` operator.
55

56
        :param tuple args: Tuple with 2 or 3 items: Config object, name of parameter
57
            to retrieve, optionally electrode to retrieve parameter for (system
58
            config is selected if no electrode is provided or value is set to None)
59

60
        :return: value of derived parameter
61

62
        Example usage:
63

64
        Initialize config and derived values objects:
65
        Note that ``DerivedValues`` is meant to be used from within the
66
        :class:`mpet.config.configuration.Config` class. Passing the entire
67
        ``Config`` object is then achieved by passing ``self``, instead of ``config``
68
        to ``DerivedValues``.
69

70
        >>> config = Config('/path/to/params_system.cfg')
71
        >>> dv = DerivedValues()
72

73
        Parameter that does not need electrode, ``t_ref``:
74

75
        >>> dv[config, 't_ref', None]
76
        7.792736808950305
77

78
        Parameter that does need electrode:
79

80
        >>> dv[config, 'csmax', 'c']
81
        22904.35071404849
82

83
        If a parameter that needs and electrode is accessed without electrode,
84
        or vice-versa, an error is raised:
85

86
        >>> dv[config, 'csmax', None]
87
        TypeError: csmax() missing 1 required positional argument: 'trode'
88

89
        >>> dv[config, 't_ref', 'c']
90
        TypeError: t_ref() takes 1 positional argument but 2 were given
91
        """
92

93
        if len(args) == 2:
4✔
94
            config, item = args
×
95
            trode = None
×
96
        elif len(args) == 3:
4✔
97
            config, item, trode = args
4✔
98
        else:
99
            raise ValueError(f"There should be 2 or 3 arguments, got {len(args)}")
×
100

101
        # set config class-wide for easy access in methods
102
        self.config = config
4✔
103

104
        # select general or electrode dict
105
        if trode is None:
4✔
106
            values = self.values
4✔
107
            func_args = ()
4✔
108
        else:
109
            values = self.values[trode]
4✔
110
            # the electrode should be given to the function as argument
111
            func_args = (trode, )
4✔
112

113
        # calculate value if not already stored
114
        if item not in values:
4✔
115
            try:
4✔
116
                func = getattr(self, item)
4✔
117
            except AttributeError:
×
118
                raise UnknownParameterError(f'Unknown parameter: {item}')
×
119
            values[item] = func(*func_args)
4✔
120

121
        return values[item]
4✔
122

123
    def Damb(self):
4✔
124
        """Ambipolar diffusivity
125
        """
126
        zp = self.config['zp']
4✔
127
        zm = self.config['zm']
4✔
128
        Dp = self.config['Dp']
4✔
129
        Dm = self.config['Dm']
4✔
130
        return ((zp - zm) * Dp * Dm) / (zp * Dp - zm * Dm)
4✔
131

132
    def tp(self):
4✔
133
        """Cation transference number
134
        """
135
        zp = self.config['zp']
×
136
        zm = self.config['zm']
×
137
        Dp = self.config['Dp']
×
138
        Dm = self.config['Dm']
×
139
        return zp * Dp / (zp * Dp - zm * Dm)
×
140

141
    def t_ref(self):
4✔
142
        """Reference time scale
143
        """
144
        return self.config['L_ref']**2 / self.config['D_ref']
4✔
145

146
    def curr_ref(self):
4✔
147
        """Reference current
148
        """
149
        return 3600. / self.config['t_ref']
4✔
150

151
    def sigma_s_ref(self):
4✔
152
        """Reference conductivity
153
        """
154
        return self.config['L_ref']**2 * constants.F**2 * constants.c_ref \
4✔
155
            / (self.config['t_ref'] * constants.k * constants.N_A * constants.T_ref)
156

157
    def currset(self):
4✔
158
        """Total current
159
        """
160
        return self.config['1C_current_density'] * self.config['Crate']  # A/m^2
4✔
161

162
    def Rser_ref(self):
4✔
163
        """Reference series resistance
164
        """
165
        return constants.k * constants.T_ref \
4✔
166
            / (constants.e * self.config['curr_ref'] * self.config['1C_current_density'])
167

168
    def csmax(self, trode):
4✔
169
        """Maximum concentration for given electrode
170
        """
171
        return self.config[trode, 'rho_s'] / constants.N_A
4✔
172

173
    def cap(self, trode):
4✔
174
        """Theoretical capacity of given electrode
175
        """
176
        capacity = constants.e * self.config['L'][trode] * (1 - self.config['poros'][trode]) \
4✔
177
            * self.config['P_L'][trode] * self.config[trode, 'rho_s']
178
        if np.all(self.config['specified_poros'][trode]):
4✔
179
            sum_porosity = 0
×
180
            for i in self.config['specified_poros'][trode]:
×
181
                sum_porosity = sum_porosity + i
×
182
            avg_porosity = sum_porosity/np.size(self.config['specified_poros'][trode])
×
183
            capacity = constants.e * self.config['L'][trode] * (1 - avg_porosity) \
×
184
                * self.config['P_L'][trode] * self.config[trode, 'rho_s']
185
        return capacity
4✔
186

187
    def numsegments(self):
4✔
188
        """Number of segments in voltage/current profile
189
        """
190
        return len(self.config['segments'])
4✔
191

192
    def L_ref(self):
4✔
193
        """Reference length scale
194
        """
195
        return self.config['L']['c']
4✔
196

197
    def D_ref(self):
4✔
198
        """Reference diffusivity
199
        """
200
        if self.config['elyteModelType'] == 'dilute':
4✔
201
            return self.config['Damb']
4✔
202
        elif self.config['elyteModelType'] == 'solid':
4✔
203
            return self.config['Damb']
4✔
204
        else:
205
            SMset = self.config["SMset"]
4✔
206
            elyte_function = import_function(self.config["SMset_filename"], SMset,
4✔
207
                                             mpet_module=f"mpet.electrolyte.{SMset}")
208
            return elyte_function()[-1]
4✔
209

210
    def z(self):
4✔
211
        """Electrode capacity ratio
212
        """
213
        if 'a' in self.config['trodes']:
4✔
214
            return self.config['c', 'cap'] / self.config['a', 'cap']
4✔
215
        else:
216
            # flat plate anode with assumed infinite supply of metal
217
            return 0.
4✔
218

219
    def limtrode(self):
4✔
220
        """Capacity-limiting electrode
221
        """
222
        if self.config['z'] < 1:
4✔
223
            return 'c'
4✔
224
        else:
225
            return 'a'
4✔
226

227
    def cs_ref(self, trode):
4✔
228
        """Reference concentration
229
        """
230
        if self.config[trode, 'type'] in constants.one_var_types:
4✔
231
            prefac = 1
4✔
232
        elif self.config[trode, 'type'] in constants.two_var_types:
4✔
233
            prefac = .5
4✔
234
        return prefac * self.config[trode, 'csmax']
4✔
235

236
    def muR_ref(self, trode):
4✔
237
        """Reference chemical potential of given electrode
238
        """
239
        muRfunc = props_am.muRfuncs(self.config, trode).muRfunc
4✔
240
        cs0bar = self.config['cs0'][trode]
4✔
241
        cs0 = np.array([cs0bar])
4✔
242

243
        solidType = self.config[trode, 'type']
4✔
244
        if solidType in constants.two_var_types:
4✔
245
            muR_ref = -muRfunc((cs0, cs0), (cs0bar, cs0bar), 0.)[0][0]
4✔
246
        elif solidType in constants.one_var_types:
4✔
247
            muR_ref = -muRfunc(cs0, cs0bar, 0.)[0]
4✔
248
        else:
249
            raise ValueError(f'Unknown solid type: {solidType}')
×
250
        return muR_ref
4✔
251

252
    def phiRef(self, trode):
4✔
253
        """Reference electrostatic potential of given electrode
254
        """
255
        return -self.config[trode, 'muR_ref'][0]
4✔
256

257
    def power_ref(self):
4✔
258
        """Reference power of the system
259
        """
260
        return constants.k*constants.T_ref * \
4✔
261
            self.config['curr_ref']*self.config["1C_current_density"]/constants.e
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc