GCC Code Coverage Report


Directory: src/athena/
File: src/athena/athena_loss.f90
Date: 2026-04-15 16:08:59
Exec Total Coverage
Lines: 98 101 97.0%
Functions: 0 0 -%
Branches: 429 855 50.2%

Line Branch Exec Source
1 module athena__loss
2 !! Module containing loss function implementations
3 !!
4 !! This module implements loss functions that quantify the difference between
5 !! model predictions and target values, guiding the optimisation process.
6 !!
7 !! Implemented loss functions:
8 !!
9 !! Mean Squared Error (MSE):
10 !! L = (1/N) Σ (y_pred - y_true)²
11 !! For regression, sensitive to outliers
12 !!
13 !! Mean Absolute Error (MAE):
14 !! L = (1/N) Σ |y_pred - y_true|
15 !! For regression, robust to outliers
16 !!
17 !! Binary Cross-Entropy:
18 !! L = -(1/N) Σ [y*log(ŷ) + (1-y)*log(1-ŷ)]
19 !! For binary classification (outputs in [0,1])
20 !!
21 !! Categorical Cross-Entropy:
22 !! L = -(1/N) Σ_i Σ_c y_{i,c} * log(ŷ_{i,c})
23 !! For multi-class classification with one-hot encoded targets
24 !!
25 !! Sparse Categorical Cross-Entropy:
26 !! L = -(1/N) Σ log(ŷ_{i,c_i})
27 !! For multi-class with integer class labels
28 !!
29 !! Huber Loss:
30 !! L = (1/N) Σ { 0.5*(y-ŷ)² if |y-ŷ| ≤ δ
31 !! { δ*(|y-ŷ| - 0.5*δ) otherwise
32 !! Combines MSE and MAE, robust to outliers while smooth near zero
33 !!
34 !! where N is number of samples, y is true value, ŷ is prediction
35 use coreutils, only: real32
36 use diffstruc, only: array_type, operator(+), operator(-), &
37 operator(*), operator(/), mean, sum, log, abs, merge, squared
38 use athena__diffstruc_extd, only: huber
39 implicit none
40
41
42 private
43
44 public :: base_loss_type
45 public :: bce_loss_type
46 public :: cce_loss_type
47 public :: mae_loss_type
48 public :: mse_loss_type
49 public :: nll_loss_type
50 public :: huber_loss_type
51
52
53 type, abstract :: base_loss_type
54 !! Abstract type for loss functions
55 character(len=:), allocatable :: name
56 !! Name of the loss function
57 real(real32) :: epsilon = 1.E-10_real32
58 !! Small value to prevent log(0)
59 integer :: batch_index = 1
60 !! Index of the batch to compute the loss for
61 integer :: sample_index = 1
62 !! Index of the sample to compute the loss for
63 contains
64 procedure(compute_base), deferred, pass(this) :: compute
65 !! Compute the loss of a model
66 end type base_loss_type
67
68 interface
69 module function compute_base(this, predicted, expected) result(output)
70 !! Compute the loss of a model
71 class(base_loss_type), intent(in), target :: this
72 !! Instance of the physics-informed neural network loss function
73 type(array_type), dimension(:,:), intent(inout), target :: predicted
74 !! Predicted values
75 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
76 expected
77 !! Expected values
78 type(array_type), pointer :: output
79 !! Physics-informed neural network loss
80 end function compute_base
81 end interface
82
83 !-------------------------------------------------------------------------------
84
85 type, extends(base_loss_type) :: bce_loss_type
86 !! Binary cross entropy loss function
87 contains
88 procedure :: compute => compute_bce
89 !! Compute the loss of a model
90 end type bce_loss_type
91
92 interface bce_loss_type
93 !! Interface for binary cross entropy loss function
94 module function setup_loss_bce() result(loss)
95 !! Set up binary cross entropy loss function
96 type(bce_loss_type) :: loss
97 !! Binary cross entropy loss function
98 end function setup_loss_bce
99 end interface bce_loss_type
100
101 !-------------------------------------------------------------------------------
102
103 type, extends(base_loss_type) :: cce_loss_type
104 !! Categorical cross entropy loss function
105 contains
106 procedure :: compute => compute_cce
107 !! Compute the loss of a model
108 end type cce_loss_type
109
110 interface cce_loss_type
111 !! Interface for categorical cross entropy loss function
112 module function setup_loss_cce() result(loss)
113 !! Set up categorical cross entropy loss function
114 type(cce_loss_type) :: loss
115 !! Categorical cross entropy loss function
116 end function setup_loss_cce
117 end interface cce_loss_type
118
119 !-------------------------------------------------------------------------------
120
121 type, extends(base_loss_type) :: mae_loss_type
122 !! Mean absolute error loss function
123 contains
124 procedure :: compute => compute_mae
125 !! Compute the loss of a model
126 end type mae_loss_type
127
128 interface mae_loss_type
129 !! Interface for mean absolute error loss function
130 module function setup_loss_mae() result(loss)
131 !! Set up mean absolute error loss function
132 type(mae_loss_type) :: loss
133 !! Mean absolute error loss function
134 end function setup_loss_mae
135 end interface mae_loss_type
136
137 !-------------------------------------------------------------------------------
138
139 type, extends(base_loss_type) :: mse_loss_type
140 !! Mean squared error loss function
141 contains
142 procedure :: compute => compute_mse
143 !! Compute the loss of a model
144 end type mse_loss_type
145
146 interface mse_loss_type
147 !! Interface for mean squared error loss function
148 module function setup_loss_mse() result(loss)
149 !! Set up mean squared error loss function
150 type(mse_loss_type) :: loss
151 !! Mean squared error loss function
152 end function setup_loss_mse
153 end interface mse_loss_type
154
155 !-------------------------------------------------------------------------------
156
157 type, extends(base_loss_type) :: nll_loss_type
158 !! Negative log likelihood loss function
159 contains
160 procedure :: compute => compute_nll
161 !! Compute the loss of a model
162 end type nll_loss_type
163
164 interface nll_loss_type
165 !! Interface for negative log likelihood loss function
166 module function setup_loss_nll() result(loss)
167 !! Set up negative log likelihood loss function
168 type(nll_loss_type) :: loss
169 !! Negative log likelihood loss function
170 end function setup_loss_nll
171 end interface nll_loss_type
172
173 !-------------------------------------------------------------------------------
174
175 type, extends(base_loss_type) :: huber_loss_type
176 !! Huber loss function
177 real(real32) :: gamma = 1._real32
178 !! Gamma value for the huber loss function
179 contains
180 procedure :: compute => compute_huber
181 !! Compute the loss of a model
182 end type huber_loss_type
183
184 interface huber_loss_type
185 !! Interface for huber loss function
186 module function setup_loss_huber() result(loss)
187 !! Set up huber loss function
188 type(huber_loss_type) :: loss
189 !! Huber loss function
190 end function setup_loss_huber
191 end interface huber_loss_type
192
193 !-------------------------------------------------------------------------------
194
195
196
197 contains
198 !###############################################################################
199 3 module function setup_loss_bce() result(loss)
200 !! Set up binary cross entropy loss function
201 implicit none
202
203 ! Local variables
204 type(bce_loss_type) :: loss
205 !! Binary cross entropy loss function
206
207
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 loss%name = 'bce'
208
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 end function setup_loss_bce
209 !-------------------------------------------------------------------------------
210 3 module function setup_loss_cce() result(loss)
211 !! Set up categorical cross entropy loss function
212 implicit none
213
214 ! Local variables
215 type(cce_loss_type) :: loss
216 !! Categorical cross entropy loss function
217
218
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 loss%name = 'cce'
219
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 end function setup_loss_cce
220 !-------------------------------------------------------------------------------
221 3 module function setup_loss_mae() result(loss)
222 !! Set up mean absolute error loss function
223 implicit none
224
225 ! Local variables
226 type(mae_loss_type) :: loss
227 !! Mean absolute error loss function
228
229
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 loss%name = 'mae'
230
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 end function setup_loss_mae
231 !-------------------------------------------------------------------------------
232 57 module function setup_loss_mse() result(loss)
233 !! Set up mean squared error loss function
234 implicit none
235
236 ! Local variables
237 type(mse_loss_type) :: loss
238 !! Mean squared error loss function
239
240
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 57 times.
57 loss%name = 'mse'
241
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
114 end function setup_loss_mse
242 !-------------------------------------------------------------------------------
243 3 module function setup_loss_nll() result(loss)
244 !! Set up negative log likelihood loss function
245 implicit none
246
247 ! Local variables
248 type(nll_loss_type) :: loss
249 !! Negative log likelihood loss function
250
251
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 loss%name = 'nll'
252
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 end function setup_loss_nll
253 !-------------------------------------------------------------------------------
254 3 module function setup_loss_huber() result(loss)
255 !! Set up huber loss function
256 implicit none
257
258 ! Local variables
259 type(huber_loss_type) :: loss
260 !! Huber loss function
261
262
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
3 loss%name = 'hub'
263
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 end function setup_loss_huber
264 !###############################################################################
265
266
267 !###############################################################################
268
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 function compute_bce(this, predicted, expected) result(output)
269 !! Compute the binary cross entropy loss of a model
270 implicit none
271
272 ! Arguments
273 class(bce_loss_type), intent(in), target :: this
274 !! Instance of the physics-informed neural network loss function
275 type(array_type), dimension(:,:), intent(inout), target :: predicted
276 !! Predicted values
277
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
2 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
278 expected
279 !! Expected values
280 type(array_type), pointer :: output
281 !! Binary cross entropy loss
282
283 ! Local variables
284 integer :: s, i
285 !! Loop indices
286 type(array_type), pointer :: ptr
287 !! Temporary pointer for calculations
288
289
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
2 output => mean(-expected(1,1) * log(predicted(1,1) + this%epsilon), dim=2)
290
14/22
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
4 if(any(shape(predicted).gt.1))then
291
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
292
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
293
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
294
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
295
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
296
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
3 ptr => mean(-expected(i,s) * log(predicted(i,s) + this%epsilon), dim=2)
297
298 5 output => output + ptr
299 end do
300 end do
301 end if
302
303 2 end function compute_bce
304 !###############################################################################
305
306
307 !###############################################################################
308
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 function compute_cce(this, predicted, expected) result(output)
309 !! Compute the categorical cross entropy loss of a model
310 implicit none
311
312 ! Arguments
313 class(cce_loss_type), intent(in), target :: this
314 !! Instance of the physics-informed neural network loss function
315 type(array_type), dimension(:,:), intent(inout), target :: predicted
316 !! Predicted values
317
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
2 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
318 expected
319 !! Expected values
320 type(array_type), pointer :: output
321 !! Categorical cross entropy loss
322
323 ! Local variables
324 integer :: s, i
325 !! Loop indices
326 type(array_type), pointer :: ptr
327 !! Temporary pointer for calculations
328
329 output => -mean( sum( &
330
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
4 expected(1,1) * log(predicted(1,1) + this%epsilon), &
331
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
6 dim=1 ), dim=2)
332
14/22
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
4 if(any(shape(predicted).gt.1))then
333
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
334
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
336
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
337
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
338 ptr => mean( sum( &
339
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
12 expected(i,s) * log(predicted(i,s) + this%epsilon), &
340
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
15 dim=1 ), dim=2)
341
342 5 output => output - ptr
343 end do
344 end do
345 end if
346
347 2 end function compute_cce
348 !###############################################################################
349
350
351 !###############################################################################
352
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 function compute_mae(this, predicted, expected) result(output)
353 !! Compute the mean absolute error of a model
354 implicit none
355
356 ! Arguments
357 class(mae_loss_type), intent(in), target :: this
358 type(array_type), dimension(:,:), intent(inout), target :: predicted
359 !! Predicted values
360
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
2 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
361 expected
362 !! Expected values
363 type(array_type), pointer :: output
364 !! Mean absolute error
365
366 ! Local variables
367 integer :: s, i
368 !! Loop indices
369 type(array_type), pointer :: ptr
370 !! Temporary pointer for calculations
371
372
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
4 output => mean( abs( predicted(1,1) - expected(1,1) ) ) / &
373
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
6 2._real32
374
14/22
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
4 if(any(shape(predicted).gt.1))then
375
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
376
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
377
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
378
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
379
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
380
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
12 ptr => mean( abs( predicted(i,s) - expected(i,s) ) ) / &
381
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
15 2._real32
382
383 5 output => output + ptr
384 end do
385 end do
386 end if
387
388 2 end function compute_mae
389 !###############################################################################
390
391
392 !###############################################################################
393
1/2
✓ Branch 0 taken 1720 times.
✗ Branch 1 not taken.
1720 function compute_mse(this, predicted, expected) result(output)
394 !! Compute the mean squared error of a model
395 implicit none
396
397 ! Arguments
398 class(mse_loss_type), intent(in), target :: this
399 !! Instance of the mean squared error loss function
400 type(array_type), dimension(:,:), intent(inout), target :: predicted
401 !! Predicted values
402
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 1720 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1720 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1720 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1720 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1720 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1720 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 1720 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 1720 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 1720 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1720 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 1720 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 1720 times.
1720 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
403 expected
404 !! Expected values
405 type(array_type), pointer :: output
406 !! Mean squared error loss
407
408 ! Local variables
409 integer :: s, i
410 !! Loop indices
411 type(array_type), pointer :: ptr
412 !! Temporary pointer for calculations
413
414
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1720 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1720 times.
3440 output => mean( squared( predicted(1,1) - expected(1,1) ) ) / &
415
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1720 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1720 times.
5160 2._real32
416
14/22
✓ Branch 0 taken 3439 times.
✓ Branch 1 taken 1719 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3439 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3439 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3439 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3439 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3439 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3439 times.
✓ Branch 20 taken 3439 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3439 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 3438 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1719 times.
5158 if(any(shape(predicted).gt.1))then
417
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
418
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
419
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
420
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
421
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
422
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
12 ptr => mean( squared( predicted(i,s) - expected(i,s) ) ) / &
423
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
15 2._real32
424
425 5 output => output + ptr
426 end do
427 end do
428 end if
429
430 1720 end function compute_mse
431 !###############################################################################
432
433
434 !###############################################################################
435
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 function compute_nll(this, predicted, expected) result(output)
436 !! Compute the negative log likelihood of a model
437 implicit none
438
439 ! Arguments
440 class(nll_loss_type), intent(in), target :: this
441 !! Instance of the physics-informed neural network loss function
442 type(array_type), dimension(:,:), intent(inout), target :: predicted
443 !! Predicted values
444
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
2 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
445 expected
446 !! Expected values
447 type(array_type), pointer :: output
448 !! Negative log likelihood loss
449
450 ! Local variables
451 integer :: s, i
452 !! Loop indices
453 type(array_type), pointer :: ptr
454 !! Temporary pointer for calculations
455
456
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
2 output => mean(-log(expected(1,1) - predicted(1,1) + this%epsilon) )
457
14/22
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
4 if(any(shape(predicted).gt.1))then
458
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
459
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
460
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
461
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
462
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
463
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
3 ptr => mean(-log(expected(i,s) - predicted(i,s) + this%epsilon) )
464
465 5 output => output + ptr
466 end do
467 end do
468 end if
469
470 2 end function compute_nll
471 !###############################################################################
472
473
474 !###############################################################################
475
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 function compute_huber(this, predicted, expected) result(output)
476 !! Compute the huber loss of a model
477 implicit none
478
479 ! Arguments
480 class(huber_loss_type), intent(in), target :: this
481 !! Instance of the huber loss function
482 type(array_type), dimension(:,:), intent(inout), target :: predicted
483 !! Predicted values
484
12/24
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 2 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 2 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 2 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 2 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
2 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
485 expected
486 !! Expected values
487 type(array_type), pointer :: output
488 !! Huber loss
489
490 ! Local variables
491 integer :: s, i
492 !! Loop indices
493 type(array_type), pointer :: ptr
494 !! Temporary pointer for calculations
495
496
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
2 ptr => predicted(1,1) - expected(1,1)
497
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
2 output => mean( huber(predicted(1,1) - expected(1,1), this%gamma) )
498
14/22
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✓ Branch 23 taken 3 times.
✓ Branch 25 taken 1 times.
✓ Branch 26 taken 2 times.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 1 times.
4 if(any(shape(predicted).gt.1))then
499
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✓ Branch 18 taken 2 times.
✓ Branch 19 taken 1 times.
3 do s = 1, size(predicted,2)
500
8/14
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 2 times.
7 do i = 1, size(predicted,1)
501
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(i.eq.1 .and. s.eq.1) cycle
502
5/10
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
6 if(.not.predicted(i,s)%allocated .or. &
503
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
3 .not.expected(i,s)%allocated) cycle
504
8/16
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 3 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
3 ptr => predicted(i,s) - expected(i,s)
505
506 5 output => output + mean( huber(ptr, this%gamma) )
507 end do
508 end do
509 end if
510
511 ! output => merge( &
512 ! 0.5_real32 * (ptr)**2._real32, &
513 ! this%gamma * (abs(ptr) - 0.5_real32 * this%gamma), &
514 ! abs(ptr) .le. this%gamma &
515 ! )
516
517 2 end function compute_huber
518 !###############################################################################
519
520
521 !###############################################################################
522 module function compute_base(this, predicted, expected) result(output)
523 !! Placeholder for compute function in base_loss_type
524 implicit none
525
526 ! Arguments
527 class(base_loss_type), intent(in), target :: this
528 !! Instance of the base loss function
529 type(array_type), dimension(:,:), intent(inout), target :: predicted
530 !! Predicted values
531 type(array_type), dimension(size(predicted,1),size(predicted,2)), intent(in) :: &
532 expected
533 !! Expected values
534 type(array_type), pointer :: output
535 !! Loss value
536
537 end function compute_base
538 !###############################################################################
539
540
11/53
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 73 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✓ Branch 40 taken 57 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 57 times.
✓ Branch 45 taken 57 times.
✓ Branch 46 taken 57 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 57 times.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✓ Branch 67 taken 57 times.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✓ Branch 70 taken 57 times.
374 end module athena__loss
541