Commit cf8d83d
Pr/rzmap covfie backend (#2344)
* Add 2D covfie field traits for RZ maps
Define CovfieRZFieldTraits for 2D (R,Z) field interpolation, mirroring
the existing 3D CovfieFieldTraits. The host pipeline uses
affine->clamp->linear->strided->array with float2 storage, while the
CUDA device path uses hardware texture interpolation for performance.
Prompt: "Replace RZMapField with covfie backend for storage and bilinear
interpolation on the R-Z grid, with CUDA texture acceleration on GPU"
Assisted-by: Claude Opus 4.6
* Add covfie-backed RZMapField data and evaluation
Add RZMapFieldData.covfie.hh with 4 ownership specializations (host
value/reference, device value/reference) using CovfieRZFieldTraits, and
RZMapField.covfie.hh which evaluates the 2D (R,Z) field via covfie and
projects Br to Cartesian Bx/By components.
Prompt: "Add covfie backend for RZMapField: create data ownership types and
field evaluation class mirroring the CartMapField covfie pattern"
Assisted-by: Claude Opus 4.6
* Add covfie RZMapField params constructor
Add RZMapFieldParams.covfie.cc with pimpl-based constructor that builds
a 2D covfie field from RZMapFieldInput, transposing from [Z][R] input
stride to covfie's (R,Z) ordering. Update RZMapFieldParams.hh to use
pimpl when covfie is enabled and ParamsDataStore when disabled.
Prompt: "Add covfie params constructor for RZMapField, mirroring
CartMapFieldParams.covfie.cc with pimpl pattern"
Assisted-by: Claude Opus 4.6
* Wire RZMapField covfie dispatch into existing headers
Add #if CELERITAS_USE_COVFIE guards to RZMapFieldData.hh and
RZMapField.hh to dispatch to covfie implementations when enabled,
preserving the original UniformGrid+Collection code path when disabled.
Guard RZMapFieldParams.cc with #if !CELERITAS_USE_COVFIE. Add
RZMapFieldParams.covfie.cc to the covfie CMake source list.
Prompt: "Wire the covfie dispatch into existing RZMapField headers and
CMakeLists.txt, matching CartMapField pattern"
Assisted-by: Claude Opus 4.6
* Add RZMapField device test for covfie field values on GPU
Add a CUDA/HIP device test that evaluates RZMapField on GPU and compares
against expected values from CUDA texture interpolation. Update the host
test expected values to use #if CELERITAS_USE_COVFIE so both covfie
(bilinear) and non-covfie (1D-per-component) code paths are tested.
Prompt: "Add device test for RZMapField covfie backend and ensure host
test works for both covfie-enabled and covfie-disabled builds"
Assisted-by: Claude Opus 4.6
* Fix non-covfie RZMapFieldTest expected values to match upstream
Update the #else branch expected values to match current upstream
develop, which changed after the cms-tiny.field.json test data was
updated.
Prompt: "Fix CI failure: non-covfie RZMapFieldTest.all expected values
are stale and don't match current upstream develop"
Assisted-by: Claude Opus 4.6
* Switch RZMapField covfie CUDA backend to software interpolation
Replace cuda_texture with cuda_device_array as the device storage
backend for the RZ field map, unifying the CUDA/HIP/CPU backend chain
to use the same affine<clamp<linear<strided<>>>> pipeline with software
interpolation on all platforms. Build the device field bottom-up using
cross-type constructors so each layer preserves its configuration during
the host-to-device transfer.
Remove incorrect CELER_FUNCTION annotations from host-only methods in
value<device>, initialize field_view pointer to nullptr, replace
std::hypot with the device-safe hypot from corecel/math/Algorithms.hh,
and fix the non-covfie stub Impl/ImplDeleter definitions to compile
without covfie. Update device test expected values to match software
interpolation (identical to host) and tighten tolerance to 1e-7.
Prompt: "Switch RZMapField covfie CUDA backend from cuda_texture to
cuda_device_array with bottom-up layer construction, fix host-only
CELER_FUNCTION annotations, and update device test expected values"
Assisted-by: Claude Sonnet 4.6
* Add RZMapFieldTest analytical interpolation validation
Add RZMapFieldTest.interp_validation with two synthetic cases whose
values at non-grid points are analytically known:
- Case 1 (both paths): Br=r, Bz=z — linear functions reproduced exactly
by both 1D-per-component and covfie bilinear interpolation
- Case 2 (covfie only): Br=r+z, Bz=r+z — bilinear exactly reproduces
linear functions with cross-axis dependence, confirming covfie does
true 2D interpolation; guarded by CELERITAS_USE_COVFIE since
1D-per-component correctly does not reproduce cross-axis variation
Prompt: "Add a test that validates RZMapField interpolation against
analytically known values using synthetic linear fields: one that varies
on a single axis (ground truth for both paths) and one that varies on
both axes (proving covfie does true 2D bilinear interpolation)"
Assisted-by: Claude Sonnet 4.6
* Widen RZMapFieldTest.device tolerance to 2e-7 for float32 GPU rounding
Covfie stores field values as float32 internally; GPU arithmetic produces
slightly different rounding from CPU for 3 of 24 sample points (~1.03e-7
relative error), just exceeding the original 1e-7 tolerance. Widening to
2e-7 accommodates float32 precision on device while remaining tight enough
to catch significant regressions.
Prompt: "Widen RZMapFieldTest.device tolerance from 1e-7 to 2e-7 to
accommodate float32 GPU rounding differences introduced by covfie's
internal float storage"
Assisted-by: Claude Sonnet 4.6
* Update SimpleCmsRZFieldAlongStepTest expected values for covfie path
- msc_rzfield: add #if CELERITAS_USE_COVFIE branch with covfie bilinear
interpolation values (displacement=0.495, angle=-0.927); the large
difference from the non-covfie values (displacement=0.552, angle=0.095)
arises because the test particle is in a region of strong cross-axis
field gradients where 1D-per-component and bilinear interpolation diverge
- msc_rzfield_finegrid: widen angle tolerance from EXPECT_SOFT_EQ to
EXPECT_SOFT_NEAR with 1e-11, accommodating a 6e-12 relative difference
due to float32 field storage in covfie
Prompt: "Update SimpleCmsRZFieldAlongStepTest to add covfie-specific
expected values for msc_rzfield where bilinear interpolation gives
physically different results from 1D-per-component in strong gradient
regions, and widen the msc_rzfield_finegrid angle tolerance to accommodate
float32 rounding from covfie's internal field storage"
Assisted-by: Claude Sonnet 4.6
* Simplify device field construction using covfie cross-type constructor
Replace 20-line bottom-up manual layer-by-layer construction with a
single cross-type field copy: field = std::make_unique<field_t>(*other.field).
covfie's cross-type field constructor propagates through all transformer
layers (affine->clamp->linear->strided), with strided's cross-type
owning_data_t constructor triggering cuda_device_array's constructor
from array_1d_like backends, performing the H2D transfer at the bottom
of the chain.
Prompt: "use the cross-copy constructor approach to simplify H2D device
field construction instead of manually building from the bottom up layer
by layer"
Assisted-by: Claude Sonnet 4.6
* Hide covfie headers from C++17 translation units
The CI has a C++17/C++20 split: library sources compile as C++20 but
some test files (e.g. AlongStep.test.cc) compile as C++17. When
CELERITAS_USE_COVFIE is ON, the include chain:
AlongStepRZMapFieldMscAction.hh -> RZMapFieldData.hh
-> RZMapFieldData.covfie.hh -> detail/CovfieRZFieldTraits.hh
-> covfie/core/parameter_pack.hpp (uses C++20 "requires")
caused C++17 builds to fail.
Fix by ensuring covfie types never appear in any .hh included by C++17
TUs:
- RZMapFieldData.hh (covfie path): define only the primary template
declaration and the const_reference/device specialization with a
void const* field_view (no covfie types). The other three
specializations remain in RZMapFieldData.covfie.hh which is only
included from .covfie.cc and .cu files.
- RZMapFieldData.covfie.hh: include RZMapFieldData.hh for the primary
template; remove the const_reference/device specialization (now in
.hh).
- RZMapField.covfie.hh: add rzmap_get_view<M> function template that
uses if constexpr (with M as template parameter so the discarded
branch is not instantiated) to either cast void const* on device or
call get_view() on host. Store ParamsRef const& instead of a direct
field view reference.
- RZMapFieldParams.covfie.cc: assign device_ref_ fields explicitly
since const_reference/device no longer has an operator=(value/device).
- AlongStepRZMapFieldMscAction.hh: remove spurious include of
RZMapFieldData.hh (the class only holds SPConstFieldParams; it never
references RZMapFieldParamsData directly).
The non-covfie build path and the CartMapField backend are unaffected.
Prompt: "The CI has a C++17/C++20 split where library source files compile
as C++20 but some test files compile as C++17. When CELERITAS_USE_COVFIE
is ON, covfie's parameter_pack.hpp uses C++20 requires clauses that leak
into C++17 TUs through the public RZMapFieldData.hh include chain. Fix
this by hiding all covfie types from public headers so that C++17 TUs
never see covfie includes. Use void const* type erasure for the device
const_reference specialization, with the cast back to the concrete view
type happening only in .cu files compiled as C++20."
Assisted-by: Claude Sonnet 4.6
* Move AlongStepRZMapFieldMscAction into covfie CMake target
The action's .cc and .cu files include RZMapField.hh, which when covfie
is enabled pulls in covfie headers requiring C++20. The file was
previously registered via the unconditional celeritas_polysource() call,
placing it in the main celeritas library target that does not directly
link Extcovfie and therefore does not inherit cxx_std_20 from covfie's
INTERFACE_COMPILE_FEATURES.
Move the action into _celer_covfie_src alongside
AlongStepCartMapFieldMscAction so it is compiled in a target that
directly links Extcovfie. Add the corresponding non-covfie fallback in
the else() branch and remove the unconditional celeritas_polysource()
call.
Prompt: "AlongStepRZMapFieldMscAction.cc includes RZMapField.hh which
pulls in covfie headers requiring C++20, but the file is compiled in a
target that does not directly link Extcovfie and therefore compiles at
C++17. AlongStepCartMapFieldMscAction avoids this because it is placed
in _celer_covfie_src which directly links Extcovfie and inherits
cxx_std_20 from covfie's INTERFACE_COMPILE_FEATURES. Apply the same fix
to AlongStepRZMapFieldMscAction."
Assisted-by: Claude Sonnet 4.6
* Add RZAdapterField to hide covfie from RZMapMagneticField.hh
RZMapMagneticField.hh included RZMapField.hh, which when covfie is
enabled pulls in covfie headers requiring C++20. This broke compilation
of any downstream .cc file (e.g. celer-g4/DetectorConstruction.cc)
that includes the header but is compiled at C++17.
Apply the same adapter pattern used by CartMapMagneticField: introduce
RZAdapterField, a plain struct whose operator() is defined in a new
RZMapMagneticField.cc. The .cc file includes RZMapField.hh and is
compiled as part of the accel library, which already links Extcovfie
and therefore compiles at C++20. The .hh now only includes
RZMapFieldParams.hh (which forward-declares RZMapFieldParamsData),
exposing no covfie types to downstream users.
Prompt: "DetectorConstruction.cc in celer-g4 includes
RZMapMagneticField.hh which pulls in RZMapField.hh and covfie headers
requiring C++20, but DetectorConstruction.cc is compiled at C++17.
CartMapMagneticField.hh avoids this by using a CartAdapterField struct
whose operator() is implemented in CartMapMagneticField.cc, keeping the
covfie include out of the header. Apply the same pattern to
RZMapMagneticField."
Assisted-by: Claude Sonnet 4.6
* Remove non-covfie RZMapField code path to match CartMapField pattern
Before this change, RZMapField had a separate Collection-based CPU
implementation predating covfie, guarded by #if !CELERITAS_USE_COVFIE
throughout. CartMapField already followed a cleaner pattern: a minimal
stub in the data header, inline CELER_NOT_CONFIGURED stubs in the params
header, and a one-line type alias in the field header. This commit brings
RZMapField into alignment with that pattern, removing ~350 lines of
duplicated guard logic.
Changes:
- Delete RZMapFieldParams.cc: its only content was non-covfie stubs, now
replaced by inline stubs in RZMapFieldParams.hh inside a
#if !(CELERITAS_USE_COVFIE || __DOXYGEN__) block, matching
CartMapFieldParams.hh exactly (Impl struct, ImplDeleter, ctor,
host_ref, device_ref all CELER_NOT_CONFIGURED or CELER_UNREACHABLE).
- Add minimal RZMapFieldParamsData<W,M> stub in RZMapFieldData.hh's
#else block (one field: FieldDriverOptions options) so the type is
always a complete primary template, mirroring CartMapFieldData.hh.
- Generalize detail::NotImplementedField from a Cart-specific class to a
template<template<Ownership, MemSpace> class ParamsData> class, keeping
using ParamsRef = NativeCRef<ParamsData> so FieldTrackPropagator<Field>
can still access Field::ParamsRef as a concrete type. Remove the
CartMapFieldData.hh include from NotImplementedField.hh (each field
header includes its own data header instead).
- Update CartMapField.hh to pass CartMapFieldParamsData explicitly:
using CartMapField = detail::NotImplementedField<CartMapFieldParamsData>
- Simplify RZMapField.hh's #else block to include RZMapFieldData.hh and
alias: using RZMapField = detail::NotImplementedField<RZMapFieldParamsData>
- Remove RZMapFieldParams.cc from src/celeritas/CMakeLists.txt SOURCES.
Add AlongStepRZMapFieldMscAction to the covfie-OFF else() branch
alongside AlongStepCartMapFieldMscAction so it links against the stubs.
- Disable RZMapFieldTest via #define RZMapFieldTest DISABLED_RZMapFieldTest
when !CELERITAS_USE_COVFIE (DISABLED_ GoogleTest pattern, matching how
Cart tests are not gated but RZ tests would fail without a field map).
- Disable SimpleCmsRZFieldAlongStepTest the same way in AlongStep.test.cc
and gate its two CTest entries on CELERITAS_USE_covfie in
test/celeritas/CMakeLists.txt to avoid the no-tests-written failure.
- Remove non-bilinear Case 1 from Fields.test.cc interp_validation since
the Collection-based interpolation path no longer exists; keep only the
bilinear cross-term check (Case 2) and relax tolerance to 2e-7.
Prompt: "RZMapField currently has a Collection-based CPU implementation
predating covfie, with many #if CELERITAS_USE_COVFIE guards scattered
across the field, data, params headers and test files. CartMapField
follows a cleaner pattern with minimal stubs and no guards in most places.
Remove the non-covfie RZMapField code path so that RZMapField matches the
CartMapField pattern exactly: a minimal complete type stub in the data
header's #else block, inline CELER_NOT_CONFIGURED stubs in the params
header, and a one-line NotImplementedField type alias in the field header.
Generalize detail::NotImplementedField to support both CartMapField and
RZMapField without duplicating it. Use the DISABLED_ GoogleTest prefix
trick (not full #if wrapping) to skip RZ tests when covfie is off, exactly
as Cart tests are handled. Do not add guards in RZ test files where the
analogous Cart code does not have them. Remove Case 1 from
interp_validation in Fields.test.cc since the non-bilinear interpolation
path is gone. Delete RZMapFieldParams.cc. Update CMakeLists to compile
AlongStepRZMapFieldMscAction in the covfie-OFF branch and gate the
SimpleCmsRZFieldAlongStep CTest entries on CELERITAS_USE_covfie."
Assisted-by: Claude Sonnet 4.6
* Remove dead non-covfie expected values from SimpleCmsRZFieldAlongStepTest
The msc_rzfield test body contained a #if CELERITAS_USE_COVFIE guard with
separate expected displacement and angle values for the non-covfie path.
Since SimpleCmsRZFieldAlongStepTest is already disabled via the DISABLED_
prefix when covfie is OFF, the #else branch was dead code that could never
execute. Remove the guard and retain only the covfie expected values.
Prompt: "Remove remaining #if CELERITAS_USE_COVFIE guards from
SimpleCmsRZFieldAlongStepTest test bodies. The whole fixture is disabled
when covfie is OFF so any #else branches with non-covfie expected values
are dead code and should be deleted."
Assisted-by: Claude Sonnet 4.6
* Relax tolerance in SimpleCmsRZFieldAlongStepTest.msc_rzfield
The displacement and angle expectations used EXPECT_SOFT_EQ (1e-12
relative tolerance) but CI hardware produces results with ~1e-8 relative
deviation from the reference values, likely due to differing FMA
instruction scheduling across GPU architectures. Switch to
EXPECT_SOFT_NEAR with 1e-7 to accommodate this cross-platform variation.
Prompt: "Relax the tolerance on the displacement and angle checks in
SimpleCmsRZFieldAlongStepTest.msc_rzfield to accommodate floating-point
variation across GPU hardware. The CI machine gives a result differing
by ~1e-8 relative error from the reference value, which exceeds the
default EXPECT_SOFT_EQ tolerance of 1e-12."
Assisted-by: Claude Sonnet 4.6
* refactor to keep field_view reference in RZMapField
* covfie patch
* Acknowledge float32 precision limit in msc_rzfield_finegrid test
In float32, the step length ~6e-7 cm is below machine epsilon at r~125
cm, causing all tracks to fail to change position in debug builds. Add a
ScopedLogStorer to explicitly capture and expect these errors in
float32+debug builds, and widen the angle tolerance for float32 builds.
Prompt: "Add ScopedLogStorer to msc_rzfield_finegrid to explicitly handle float32 precision limit where step length is below machine epsilon, and widen angle tolerance for float32 builds"
Assisted-by: Claude Sonnet 4.6
* Return zero outside field grid in RZMapField
Store grid bounds from RZMapFieldInput in RZMapFieldParamsData and add
a bounds check in RZMapField::operator(). Without this, covfie clamps
out-of-bounds queries to boundary values, causing NaN in the RK error
state when step length is infinite (vacuum track with no cross sections).
Prompt: "Return zero outside field grid bounds in RZMapField: store min/max bounds from RZMapFieldInput in RZMapFieldParamsData and check them in RZMapField::operator()"
Assisted-by: Claude Sonnet 4.6
---------
Co-authored-by: Sakib Rahman <srahman1@bnl.gov>1 parent ab0b5d5 commit cf8d83d
21 files changed
Lines changed: 840 additions & 314 deletions
File tree
- src
- accel
- celeritas
- alongstep
- field
- detail
- test/celeritas
- field
- global
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
167 | 167 | | |
168 | 168 | | |
169 | 169 | | |
170 | | - | |
| 170 | + | |
171 | 171 | | |
172 | 172 | | |
173 | 173 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
17 | 31 | | |
18 | | - | |
| 32 | + | |
19 | 33 | | |
20 | 34 | | |
21 | 35 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
66 | 65 | | |
67 | 66 | | |
68 | 67 | | |
| |||
196 | 195 | | |
197 | 196 | | |
198 | 197 | | |
| 198 | + | |
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
| 202 | + | |
| 203 | + | |
202 | 204 | | |
203 | 205 | | |
204 | 206 | | |
| |||
223 | 225 | | |
224 | 226 | | |
225 | 227 | | |
| 228 | + | |
| 229 | + | |
226 | 230 | | |
227 | 231 | | |
228 | 232 | | |
| |||
370 | 374 | | |
371 | 375 | | |
372 | 376 | | |
373 | | - | |
374 | 377 | | |
375 | 378 | | |
376 | 379 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
18 | 17 | | |
19 | 18 | | |
20 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
14 | 16 | | |
15 | 17 | | |
16 | 18 | | |
17 | 19 | | |
18 | 20 | | |
19 | | - | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | | - | |
12 | | - | |
13 | | - | |
14 | | - | |
15 | | - | |
16 | | - | |
17 | | - | |
18 | | - | |
19 | | - | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
20 | 15 | | |
| 16 | + | |
21 | 17 | | |
22 | 18 | | |
23 | 19 | | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | | - | |
35 | | - | |
36 | | - | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
46 | | - | |
47 | | - | |
48 | | - | |
49 | | - | |
50 | | - | |
51 | | - | |
52 | | - | |
53 | | - | |
54 | | - | |
55 | | - | |
56 | | - | |
57 | | - | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
67 | | - | |
68 | | - | |
69 | | - | |
70 | | - | |
71 | | - | |
72 | | - | |
73 | | - | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
79 | | - | |
80 | | - | |
81 | | - | |
82 | | - | |
83 | | - | |
84 | | - | |
85 | | - | |
86 | | - | |
87 | | - | |
88 | | - | |
89 | | - | |
90 | | - | |
91 | | - | |
92 | | - | |
93 | | - | |
94 | | - | |
95 | | - | |
96 | | - | |
97 | | - | |
98 | | - | |
99 | | - | |
100 | | - | |
101 | | - | |
102 | | - | |
103 | | - | |
104 | | - | |
105 | | - | |
106 | | - | |
107 | | - | |
| 20 | + | |
| 21 | + | |
108 | 22 | | |
109 | 23 | | |
| 24 | + | |
0 commit comments