Add diagram workbench UI with Modelica DoF coaching and ISO glyphs.
Ship the Next.js cycle editor with CAD chrome, technical HX symbols, Fixed/Free boundary guidance, and secondary water/air pressure drop support in the solver stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,7 +22,10 @@ fn test_verbose_config_default_is_disabled() {
|
||||
|
||||
// All features should be disabled by default for backward compatibility
|
||||
assert!(!config.enabled, "enabled should be false by default");
|
||||
assert!(!config.log_residuals, "log_residuals should be false by default");
|
||||
assert!(
|
||||
!config.log_residuals,
|
||||
"log_residuals should be false by default"
|
||||
);
|
||||
assert!(
|
||||
!config.log_jacobian_condition,
|
||||
"log_jacobian_condition should be false by default"
|
||||
@@ -48,8 +51,14 @@ fn test_verbose_config_all_enabled() {
|
||||
|
||||
assert!(config.enabled, "enabled should be true");
|
||||
assert!(config.log_residuals, "log_residuals should be true");
|
||||
assert!(config.log_jacobian_condition, "log_jacobian_condition should be true");
|
||||
assert!(config.log_solver_switches, "log_solver_switches should be true");
|
||||
assert!(
|
||||
config.log_jacobian_condition,
|
||||
"log_jacobian_condition should be true"
|
||||
);
|
||||
assert!(
|
||||
config.log_solver_switches,
|
||||
"log_solver_switches should be true"
|
||||
);
|
||||
assert!(config.dump_final_state, "dump_final_state should be true");
|
||||
}
|
||||
|
||||
@@ -86,7 +95,10 @@ fn test_verbose_config_is_any_enabled() {
|
||||
log_residuals: true,
|
||||
..Default::default()
|
||||
};
|
||||
assert!(config.is_any_enabled(), "should be true when one feature is enabled");
|
||||
assert!(
|
||||
config.is_any_enabled(),
|
||||
"should be true when one feature is enabled"
|
||||
);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -102,6 +114,7 @@ fn test_iteration_diagnostics_creation() {
|
||||
alpha: Some(0.5),
|
||||
jacobian_frozen: true,
|
||||
jacobian_condition: Some(1e3),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(diag.iteration, 5);
|
||||
@@ -122,6 +135,7 @@ fn test_iteration_diagnostics_without_alpha() {
|
||||
alpha: None,
|
||||
jacobian_frozen: false,
|
||||
jacobian_condition: None,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(diag.alpha, None);
|
||||
@@ -139,7 +153,9 @@ fn test_jacobian_condition_number_well_conditioned() {
|
||||
let entries = vec![(0, 0, 2.0), (1, 1, 1.0)];
|
||||
let j = JacobianMatrix::from_builder(&entries, 2, 2);
|
||||
|
||||
let cond = j.estimate_condition_number().expect("should compute condition number");
|
||||
let cond = j
|
||||
.estimate_condition_number()
|
||||
.expect("should compute condition number");
|
||||
|
||||
// Condition number of diagonal matrix is max/min diagonal entry
|
||||
assert!(
|
||||
@@ -152,15 +168,12 @@ fn test_jacobian_condition_number_well_conditioned() {
|
||||
#[test]
|
||||
fn test_jacobian_condition_number_ill_conditioned() {
|
||||
// Nearly singular matrix
|
||||
let entries = vec![
|
||||
(0, 0, 1.0),
|
||||
(0, 1, 1.0),
|
||||
(1, 0, 1.0),
|
||||
(1, 1, 1.0000001),
|
||||
];
|
||||
let entries = vec![(0, 0, 1.0), (0, 1, 1.0), (1, 0, 1.0), (1, 1, 1.0000001)];
|
||||
let j = JacobianMatrix::from_builder(&entries, 2, 2);
|
||||
|
||||
let cond = j.estimate_condition_number().expect("should compute condition number");
|
||||
let cond = j
|
||||
.estimate_condition_number()
|
||||
.expect("should compute condition number");
|
||||
|
||||
assert!(
|
||||
cond > 1e6,
|
||||
@@ -175,7 +188,9 @@ fn test_jacobian_condition_number_identity() {
|
||||
let entries = vec![(0, 0, 1.0), (1, 1, 1.0), (2, 2, 1.0)];
|
||||
let j = JacobianMatrix::from_builder(&entries, 3, 3);
|
||||
|
||||
let cond = j.estimate_condition_number().expect("should compute condition number");
|
||||
let cond = j
|
||||
.estimate_condition_number()
|
||||
.expect("should compute condition number");
|
||||
|
||||
assert!(
|
||||
(cond - 1.0).abs() < 1e-10,
|
||||
@@ -191,10 +206,7 @@ fn test_jacobian_condition_number_empty_matrix() {
|
||||
|
||||
let cond = j.estimate_condition_number();
|
||||
|
||||
assert!(
|
||||
cond.is_none(),
|
||||
"Expected None for empty matrix"
|
||||
);
|
||||
assert!(cond.is_none(), "Expected None for empty matrix");
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
@@ -220,10 +232,7 @@ fn test_solver_switch_event_creation() {
|
||||
|
||||
#[test]
|
||||
fn test_solver_type_display() {
|
||||
assert_eq!(
|
||||
format!("{}", SolverType::NewtonRaphson),
|
||||
"Newton-Raphson"
|
||||
);
|
||||
assert_eq!(format!("{}", SolverType::NewtonRaphson), "Newton-Raphson");
|
||||
assert_eq!(
|
||||
format!("{}", SolverType::SequentialSubstitution),
|
||||
"Sequential Substitution"
|
||||
@@ -232,7 +241,10 @@ fn test_solver_type_display() {
|
||||
|
||||
#[test]
|
||||
fn test_switch_reason_display() {
|
||||
assert_eq!(format!("{}", SwitchReason::Divergence), "divergence detected");
|
||||
assert_eq!(
|
||||
format!("{}", SwitchReason::Divergence),
|
||||
"divergence detected"
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", SwitchReason::SlowConvergence),
|
||||
"slow convergence"
|
||||
@@ -283,6 +295,7 @@ fn test_convergence_diagnostics_push_iteration() {
|
||||
alpha: None,
|
||||
jacobian_frozen: false,
|
||||
jacobian_condition: None,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
diag.push_iteration(IterationDiagnostics {
|
||||
@@ -292,6 +305,7 @@ fn test_convergence_diagnostics_push_iteration() {
|
||||
alpha: Some(1.0),
|
||||
jacobian_frozen: false,
|
||||
jacobian_condition: Some(100.0),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
assert_eq!(diag.iteration_history.len(), 2);
|
||||
@@ -410,6 +424,7 @@ fn test_convergence_diagnostics_json_serialization() {
|
||||
alpha: Some(1.0),
|
||||
jacobian_frozen: false,
|
||||
jacobian_condition: Some(100.0),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
diag.push_switch(SolverSwitchEvent {
|
||||
@@ -439,16 +454,18 @@ fn test_convergence_diagnostics_round_trip() {
|
||||
|
||||
// Serialize to JSON
|
||||
let json = serde_json::to_string(&diag).expect("Should serialize");
|
||||
|
||||
|
||||
// Deserialize back
|
||||
let restored: ConvergenceDiagnostics =
|
||||
serde_json::from_str(&json).expect("Should deserialize");
|
||||
|
||||
let restored: ConvergenceDiagnostics = serde_json::from_str(&json).expect("Should deserialize");
|
||||
|
||||
assert_eq!(restored.iterations, 25);
|
||||
assert!((restored.final_residual - 1e-8).abs() < 1e-20);
|
||||
assert!(restored.converged);
|
||||
assert_eq!(restored.timing_ms, 100);
|
||||
assert_eq!(restored.final_solver, Some(SolverType::SequentialSubstitution));
|
||||
assert_eq!(
|
||||
restored.final_solver,
|
||||
Some(SolverType::SequentialSubstitution)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -457,7 +474,7 @@ fn test_dump_diagnostics_json_format() {
|
||||
diag.iterations = 10;
|
||||
diag.final_residual = 1e-4;
|
||||
diag.converged = false;
|
||||
|
||||
|
||||
let json_output = diag.dump_diagnostics(VerboseOutputFormat::Json);
|
||||
assert!(json_output.starts_with('{'));
|
||||
// to_string_pretty adds spaces after colons
|
||||
@@ -471,7 +488,7 @@ fn test_dump_diagnostics_log_format() {
|
||||
diag.iterations = 10;
|
||||
diag.final_residual = 1e-4;
|
||||
diag.converged = false;
|
||||
|
||||
|
||||
let log_output = diag.dump_diagnostics(VerboseOutputFormat::Log);
|
||||
assert!(log_output.contains("Convergence Diagnostics Summary"));
|
||||
assert!(log_output.contains("Converged: NO"));
|
||||
|
||||
Reference in New Issue
Block a user