Skip to content

Commit 14a6aa7

Browse files
Refactor LinearVerbosity to use SciMLLogging's @verbosity_specifier macro
This change updates LinearVerbosity to use the @verbosity_specifier macro from SciMLLogging instead of manual struct definition and constructor implementations. Changes: - Replace @concrete struct with @verbosity_specifier macro - Remove manual keyword constructor (now auto-generated by macro) - Remove manual preset constructors (now auto-generated by macro) - Remove _resolve_arg_value helper function - Keep group classification constants for backwards compatibility - Keep option_group and group_options helper functions - Bump SciMLLogging minimum version to 1.7 (required for @verbosity_specifier) The macro generates: - Parametric struct for type stability - Preset constructors for None, Minimal, Standard, Detailed, All - Keyword constructor with precedence: individual > group > preset 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent 409ab7f commit 14a6aa7

File tree

3 files changed

+139
-222
lines changed

3 files changed

+139
-222
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ RecursiveFactorization = "0.2.26"
128128
Reexport = "1.2.2"
129129
SafeTestsets = "0.1"
130130
SciMLBase = "2.128"
131-
SciMLLogging = "1.3.1"
131+
SciMLLogging = "1.7"
132132
SciMLOperators = "1.13"
133133
Setfield = "1.1.1"
134134
SparseArrays = "1.10"

src/LinearSolve.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ using SciMLBase: SciMLBase, LinearAliasSpecifier, AbstractSciMLOperator,
2121
using SciMLOperators: SciMLOperators, AbstractSciMLOperator, IdentityOperator,
2222
MatrixOperator,
2323
has_ldiv!, issquare, has_concretization
24-
using SciMLLogging: SciMLLogging, @SciMLMessage, verbosity_to_int, AbstractVerbositySpecifier, AbstractMessageLevel, AbstractVerbosityPreset,
24+
using SciMLLogging: SciMLLogging, @SciMLMessage, verbosity_to_int,
25+
AbstractVerbositySpecifier, AbstractMessageLevel, AbstractVerbosityPreset,
2526
Silent, InfoLevel, WarnLevel, CustomLevel, None, Minimal, Standard, Detailed, All
2627
using Setfield: @set, @set!
2728
using DocStringExtensions: DocStringExtensions

src/verbosity.jl

Lines changed: 136 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,127 @@
1-
"""
1+
SciMLLogging.@verbosity_specifier LinearVerbosity begin
2+
toggles = (
3+
:default_lu_fallback,
4+
:no_right_preconditioning,
5+
:using_IterativeSolvers,
6+
:IterativeSolvers_iterations,
7+
:KrylovKit_verbosity,
8+
:KrylovJL_verbosity,
9+
:HYPRE_verbosity,
10+
:pardiso_verbosity,
11+
:blas_errors,
12+
:blas_invalid_args,
13+
:blas_info,
14+
:blas_success,
15+
:condition_number,
16+
:convergence_failure,
17+
:solver_failure,
18+
:max_iters
19+
)
20+
21+
presets = (
22+
None = (
23+
default_lu_fallback = Silent(),
24+
no_right_preconditioning = Silent(),
25+
using_IterativeSolvers = Silent(),
26+
IterativeSolvers_iterations = Silent(),
27+
KrylovKit_verbosity = Silent(),
28+
KrylovJL_verbosity = Silent(),
29+
HYPRE_verbosity = Silent(),
30+
pardiso_verbosity = Silent(),
31+
blas_errors = Silent(),
32+
blas_invalid_args = Silent(),
33+
blas_info = Silent(),
34+
blas_success = Silent(),
35+
condition_number = Silent(),
36+
convergence_failure = Silent(),
37+
solver_failure = Silent(),
38+
max_iters = Silent()
39+
),
40+
Minimal = (
41+
default_lu_fallback = Silent(),
42+
no_right_preconditioning = Silent(),
43+
using_IterativeSolvers = Silent(),
44+
IterativeSolvers_iterations = Silent(),
45+
KrylovKit_verbosity = Silent(),
46+
KrylovJL_verbosity = Silent(),
47+
HYPRE_verbosity = Silent(),
48+
pardiso_verbosity = Silent(),
49+
blas_errors = WarnLevel(),
50+
blas_invalid_args = WarnLevel(),
51+
blas_info = Silent(),
52+
blas_success = Silent(),
53+
condition_number = Silent(),
54+
convergence_failure = Silent(),
55+
solver_failure = Silent(),
56+
max_iters = Silent()
57+
),
58+
Standard = (
59+
default_lu_fallback = Silent(),
60+
no_right_preconditioning = Silent(),
61+
using_IterativeSolvers = Silent(),
62+
IterativeSolvers_iterations = Silent(),
63+
KrylovKit_verbosity = CustomLevel(1),
64+
KrylovJL_verbosity = Silent(),
65+
HYPRE_verbosity = InfoLevel(),
66+
pardiso_verbosity = Silent(),
67+
blas_errors = WarnLevel(),
68+
blas_invalid_args = WarnLevel(),
69+
blas_info = Silent(),
70+
blas_success = Silent(),
71+
condition_number = Silent(),
72+
convergence_failure = WarnLevel(),
73+
solver_failure = WarnLevel(),
74+
max_iters = WarnLevel()
75+
),
76+
Detailed = (
77+
default_lu_fallback = WarnLevel(),
78+
no_right_preconditioning = InfoLevel(),
79+
using_IterativeSolvers = InfoLevel(),
80+
IterativeSolvers_iterations = Silent(),
81+
KrylovKit_verbosity = CustomLevel(2),
82+
KrylovJL_verbosity = CustomLevel(1),
83+
HYPRE_verbosity = InfoLevel(),
84+
pardiso_verbosity = CustomLevel(1),
85+
blas_errors = WarnLevel(),
86+
blas_invalid_args = WarnLevel(),
87+
blas_info = InfoLevel(),
88+
blas_success = InfoLevel(),
89+
condition_number = Silent(),
90+
convergence_failure = WarnLevel(),
91+
solver_failure = WarnLevel(),
92+
max_iters = WarnLevel()
93+
),
94+
All = (
95+
default_lu_fallback = WarnLevel(),
96+
no_right_preconditioning = InfoLevel(),
97+
using_IterativeSolvers = InfoLevel(),
98+
IterativeSolvers_iterations = InfoLevel(),
99+
KrylovKit_verbosity = CustomLevel(3),
100+
KrylovJL_verbosity = CustomLevel(1),
101+
HYPRE_verbosity = InfoLevel(),
102+
pardiso_verbosity = CustomLevel(1),
103+
blas_errors = WarnLevel(),
104+
blas_invalid_args = WarnLevel(),
105+
blas_info = InfoLevel(),
106+
blas_success = InfoLevel(),
107+
condition_number = InfoLevel(),
108+
convergence_failure = WarnLevel(),
109+
solver_failure = WarnLevel(),
110+
max_iters = WarnLevel()
111+
)
112+
)
113+
114+
groups = (
115+
error_control = (:default_lu_fallback, :blas_errors, :blas_invalid_args),
116+
performance = (:no_right_preconditioning,),
117+
numerical = (:using_IterativeSolvers, :IterativeSolvers_iterations,
118+
:KrylovKit_verbosity, :KrylovJL_verbosity, :HYPRE_verbosity,
119+
:pardiso_verbosity, :blas_info, :blas_success, :condition_number,
120+
:convergence_failure, :solver_failure, :max_iters)
121+
)
122+
end
123+
124+
@doc """
2125
LinearVerbosity <: AbstractVerbositySpecifier
3126
4127
Verbosity configuration for LinearSolve.jl solvers, providing fine-grained control over
@@ -68,225 +191,15 @@ verbose = LinearVerbosity(
68191
blas_errors = SciMLLogging.ErrorLevel() # Override specific field
69192
)
70193
```
71-
"""
72-
LinearSolve.@concrete struct LinearVerbosity <:
73-
AbstractVerbositySpecifier
74-
# Error control
75-
default_lu_fallback
76-
# Performance
77-
no_right_preconditioning
78-
# Numerical
79-
using_IterativeSolvers
80-
IterativeSolvers_iterations
81-
KrylovKit_verbosity
82-
KrylovJL_verbosity
83-
HYPRE_verbosity
84-
pardiso_verbosity
85-
blas_errors
86-
blas_invalid_args
87-
blas_info
88-
blas_success
89-
condition_number
90-
convergence_failure
91-
solver_failure
92-
max_iters
93-
end
94-
95-
function LinearVerbosity(;
96-
error_control = nothing, performance = nothing, numerical = nothing, kwargs...)
97-
# Fast path for default construction (type-stable)
98-
if error_control === nothing && performance === nothing &&
99-
numerical === nothing && isempty(kwargs)
100-
return LinearVerbosity(
101-
Silent(),
102-
Silent(),
103-
Silent(),
104-
Silent(),
105-
CustomLevel(1), # WARN_LEVEL in KrylovKit.jl
106-
Silent(),
107-
InfoLevel(),
108-
Silent(),
109-
WarnLevel(),
110-
WarnLevel(),
111-
Silent(),
112-
Silent(),
113-
Silent(),
114-
WarnLevel(),
115-
WarnLevel(),
116-
WarnLevel())
117-
end
118-
119-
# Validate group arguments
120-
if error_control !== nothing && !(error_control isa AbstractMessageLevel)
121-
throw(ArgumentError("error_control must be a SciMLLogging.AbstractMessageLevel, got $(typeof(error_control))"))
122-
end
123-
if performance !== nothing && !(performance isa AbstractMessageLevel)
124-
throw(ArgumentError("performance must be a SciMLLogging.AbstractMessageLevel, got $(typeof(performance))"))
125-
end
126-
if numerical !== nothing && !(numerical isa AbstractMessageLevel)
127-
throw(ArgumentError("numerical must be a SciMLLogging.AbstractMessageLevel, got $(typeof(numerical))"))
128-
end
129-
130-
# Validate individual kwargs
131-
for (key, value) in kwargs
132-
if !(key in error_control_options || key in performance_options ||
133-
key in numerical_options)
134-
throw(ArgumentError("Unknown verbosity option: $key. Valid options are: $(tuple(error_control_options..., performance_options..., numerical_options...))"))
135-
end
136-
if !(value isa AbstractMessageLevel)
137-
throw(ArgumentError("$key must be a SciMLLogging.AbstractMessageLevel, got $(typeof(value))"))
138-
end
139-
end
140-
141-
# Build arguments using NamedTuple for type stability
142-
default_args = (
143-
default_lu_fallback = Silent(),
144-
no_right_preconditioning = Silent(),
145-
using_IterativeSolvers = Silent(),
146-
IterativeSolvers_iterations = Silent(),
147-
KrylovKit_verbosity = CustomLevel(1), # WARN_LEVEL in KrylovKit.jl
148-
KrylovJL_verbosity = Silent(),
149-
HYPRE_verbosity = InfoLevel(),
150-
pardiso_verbosity = Silent(),
151-
blas_errors = WarnLevel(),
152-
blas_invalid_args = WarnLevel(),
153-
blas_info = Silent(),
154-
blas_success = Silent(),
155-
condition_number=Silent(),
156-
convergence_failure=WarnLevel(),
157-
solver_failure=WarnLevel(),
158-
max_iters=WarnLevel()
159-
)
160-
161-
# Apply group-level settings
162-
final_args = if error_control !== nothing || performance !== nothing ||
163-
numerical !== nothing
164-
NamedTuple{keys(default_args)}(
165-
_resolve_arg_value(
166-
key, default_args[key], error_control, performance, numerical)
167-
for key in keys(default_args)
168-
)
169-
else
170-
default_args
171-
end
172-
173-
# Apply individual overrides
174-
if !isempty(kwargs)
175-
final_args = merge(final_args, NamedTuple(kwargs))
176-
end
177-
178-
LinearVerbosity(values(final_args)...)
179-
end
180-
181-
# Constructor for verbosity presets following the hierarchical levels:
182-
# None < Minimal < Standard < Detailed < All
183-
# Each level includes all messages from levels below it plus additional ones
184-
function LinearVerbosity(verbose::AbstractVerbosityPreset)
185-
if verbose isa Minimal
186-
# Minimal: Only fatal errors and critical warnings (BLAS errors/invalid args)
187-
LinearVerbosity(
188-
default_lu_fallback = Silent(),
189-
no_right_preconditioning = Silent(),
190-
using_IterativeSolvers = Silent(),
191-
IterativeSolvers_iterations = Silent(),
192-
KrylovKit_verbosity = Silent(),
193-
KrylovJL_verbosity = Silent(),
194-
HYPRE_verbosity = Silent(),
195-
pardiso_verbosity = Silent(),
196-
blas_errors = WarnLevel(),
197-
blas_invalid_args = WarnLevel(),
198-
blas_info = Silent(),
199-
blas_success = Silent(),
200-
condition_number = Silent(),
201-
convergence_failure = Silent(),
202-
solver_failure = Silent(),
203-
max_iters = Silent()
204-
)
205-
elseif verbose isa Standard
206-
# Standard: Everything from Minimal + non-fatal warnings
207-
LinearVerbosity()
208-
elseif verbose isa Detailed
209-
# Detailed: Everything from Standard + debugging/solver behavior
210-
LinearVerbosity(
211-
default_lu_fallback = WarnLevel(),
212-
no_right_preconditioning = InfoLevel(),
213-
using_IterativeSolvers = InfoLevel(),
214-
IterativeSolvers_iterations = Silent(),
215-
KrylovKit_verbosity = CustomLevel(2), # STARTSTOP_LEVEL in KrylovKit.jl
216-
KrylovJL_verbosity = CustomLevel(1), # verbose = true in Krylov.jl
217-
HYPRE_verbosity = InfoLevel(),
218-
pardiso_verbosity = CustomLevel(1), # verbose = true in Pardiso.jl
219-
blas_errors = WarnLevel(),
220-
blas_invalid_args = WarnLevel(),
221-
blas_info = InfoLevel(),
222-
blas_success = InfoLevel(),
223-
condition_number = Silent(),
224-
convergence_failure = WarnLevel(),
225-
solver_failure = WarnLevel(),
226-
max_iters = WarnLevel()
227-
)
228-
elseif verbose isa All
229-
# All: Maximum verbosity - every possible logging message at InfoLevel
230-
LinearVerbosity(
231-
default_lu_fallback = WarnLevel(),
232-
no_right_preconditioning = InfoLevel(),
233-
using_IterativeSolvers = InfoLevel(),
234-
IterativeSolvers_iterations = InfoLevel(),
235-
KrylovKit_verbosity = CustomLevel(3), # EACHITERATION_LEVEL in KrylovKit.jl
236-
KrylovJL_verbosity = CustomLevel(1),
237-
HYPRE_verbosity = InfoLevel(),
238-
pardiso_verbosity = CustomLevel(1), # verbsoe = true in Pardiso.jl
239-
blas_errors = WarnLevel(),
240-
blas_invalid_args = WarnLevel(),
241-
blas_info = InfoLevel(),
242-
blas_success = InfoLevel(),
243-
condition_number = InfoLevel(),
244-
convergence_failure = WarnLevel(),
245-
solver_failure = WarnLevel(),
246-
max_iters = WarnLevel()
247-
)
248-
end
249-
end
194+
""" LinearVerbosity
250195

251-
@inline function LinearVerbosity(verbose::None)
252-
LinearVerbosity(
253-
Silent(),
254-
Silent(),
255-
Silent(),
256-
Silent(),
257-
Silent(),
258-
Silent(),
259-
Silent(),
260-
Silent(),
261-
Silent(),
262-
Silent(),
263-
Silent(),
264-
Silent(),
265-
Silent(),
266-
Silent(),
267-
Silent(),
268-
Silent())
269-
end
270-
271-
# Helper function to resolve argument values based on group membership
272-
@inline function _resolve_arg_value(key::Symbol, default_val, error_control, performance, numerical)
273-
if key in error_control_options && error_control !== nothing
274-
return error_control
275-
elseif key in performance_options && performance !== nothing
276-
return performance
277-
elseif key in numerical_options && numerical !== nothing
278-
return numerical
279-
else
280-
return default_val
281-
end
282-
end
283-
284-
# Group classifications
196+
# Group classifications (for backwards compatibility)
285197
const error_control_options = (:default_lu_fallback, :blas_errors, :blas_invalid_args)
286198
const performance_options = (:no_right_preconditioning,)
287199
const numerical_options = (:using_IterativeSolvers, :IterativeSolvers_iterations,
288-
:KrylovKit_verbosity, :KrylovJL_verbosity, :HYPRE_verbosity, :pardiso_verbosity,
289-
:blas_info, :blas_success, :condition_number, :convergence_failure, :solver_failure, :max_iters)
200+
:KrylovKit_verbosity, :KrylovJL_verbosity, :HYPRE_verbosity,
201+
:pardiso_verbosity, :blas_info, :blas_success, :condition_number,
202+
:convergence_failure, :solver_failure, :max_iters)
290203

291204
function option_group(option::Symbol)
292205
if option in error_control_options
@@ -303,12 +216,15 @@ end
303216
# Get all options in a group
304217
function group_options(verbosity::LinearVerbosity, group::Symbol)
305218
if group === :error_control
306-
return NamedTuple{error_control_options}(getproperty(verbosity, opt) for opt in error_control_options)
219+
return NamedTuple{error_control_options}(getproperty(verbosity, opt)
220+
for opt in error_control_options)
307221
elseif group === :performance
308-
return NamedTuple{performance_options}(getproperty(verbosity, opt) for opt in performance_options)
222+
return NamedTuple{performance_options}(getproperty(verbosity, opt)
223+
for opt in performance_options)
309224
elseif group === :numerical
310-
return NamedTuple{numerical_options}(getproperty(verbosity, opt) for opt in numerical_options)
225+
return NamedTuple{numerical_options}(getproperty(verbosity, opt)
226+
for opt in numerical_options)
311227
else
312228
error("Unknown group: $group")
313229
end
314-
end
230+
end

0 commit comments

Comments
 (0)