1+ #!/usr/bin/env python3
2+ """
3+ RM3 Regular Waves Regression Test Comparison
4+
5+ This script compares the RM3 regular waves test results with reference data and generates
6+ comparison plots using the standardized template.
7+
8+ Usage:
9+ python compare_reg_waves.py <reference_file> <test_file>
10+ """
11+
12+ import sys
13+ import os
14+ from pathlib import Path
15+ import numpy as np
16+
17+ # Import the comparison template
18+ sys .path .append (os .path .join (os .path .dirname (__file__ ), '../utilities' ))
19+ from compare_template import run_multi_column_comparison
20+
21+ def main ():
22+ if len (sys .argv ) == 1 or (len (sys .argv ) == 3 and sys .argv [1 ] == 'default' ):
23+ # Use default reference and result file locations
24+ ref_file = os .path .join (os .path .dirname (__file__ ), ".." , "reference_data" , "rm3" , "reg_waves" , "hc_ref_rm3_reg_waves.txt" )
25+
26+ # Find the result file
27+ build_dir = os .environ .get ('HYDROCHRONO_BUILD_DIR' , 'C:/code/HydroChrono/build' )
28+ test_file = os .path .join (build_dir , "bin" , "tests" , "regression" , "rm3" , "results" , "CHRONO_RM3_REG_WAVES.txt" )
29+ elif len (sys .argv ) == 3 :
30+ ref_file = sys .argv [1 ]
31+ test_file = sys .argv [2 ]
32+ else :
33+ print ("Usage: python compare_reg_waves.py <reference_file> <test_file>" )
34+ print (" or: python compare_reg_waves.py default" )
35+ sys .exit (1 )
36+
37+ # RM3 Regular Waves specific configuration
38+ test_name = "RM3 Regular Waves Test"
39+ executable_patterns = ["rm3_reg_waves_test" , "rm3_reg_waves_test.exe" ]
40+
41+ # Define the columns to plot and their configurations
42+ test_configs = [
43+ {
44+ 'column_index' : 1 , # Float Heave
45+ 'test_name' : f"{ test_name } - Float Heave" ,
46+ 'y_label' : "Float Heave (m)" ,
47+ 'validation_tolerance' : (1e-4 , 0.02 ) # RM3-specific tolerance
48+ },
49+ {
50+ 'column_index' : 2 , # Plate Heave
51+ 'test_name' : f"{ test_name } - Plate Heave" ,
52+ 'y_label' : "Plate Heave (m)" ,
53+ 'validation_tolerance' : (1e-4 , 0.02 ) # RM3-specific tolerance
54+ },
55+ {
56+ 'column_index' : 3 , # Float Drift
57+ 'test_name' : f"{ test_name } - Float Drift" ,
58+ 'y_label' : "Float Drift (m)" ,
59+ 'validation_tolerance' : (1e-4 , 0.02 ) # RM3-specific tolerance
60+ }
61+ ]
62+
63+ try :
64+ # Load data for additional RM3-specific validations
65+ ref_data = np .loadtxt (ref_file , skiprows = 1 ) # Skip header line
66+ test_data = np .loadtxt (test_file , skiprows = 1 ) # Skip header line
67+
68+ # Show where the plots will be saved
69+ test_file_path = Path (test_file )
70+ plots_dir = test_file_path .parent / "plots"
71+ plots_dir .mkdir (parents = True , exist_ok = True )
72+ print (f"Plots will be saved to: { plots_dir } " )
73+
74+ # Create temporary files with interpolated data to match time steps
75+ import tempfile
76+
77+ # Interpolate reference data to match test data time steps
78+ nval = test_data .shape [0 ]
79+ x = np .linspace (test_data [0 , 0 ], test_data [nval - 1 , 0 ], nval )
80+
81+ # Interpolate the float heave, plate heave, and float drift data
82+ floatHeaveRef = np .interp (x , ref_data [:,0 ], ref_data [:,1 ])
83+ plateHeaveRef = np .interp (x , ref_data [:,0 ], ref_data [:,2 ])
84+ floatDriftRef = np .interp (x , ref_data [:,0 ], ref_data [:,3 ])
85+
86+ # Create interpolated reference data
87+ ref_data_interp = np .column_stack ((x , floatHeaveRef , plateHeaveRef , floatDriftRef ))
88+
89+ # Create temporary files with interpolated data
90+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.txt' , delete = False ) as temp_ref :
91+ np .savetxt (temp_ref .name , ref_data_interp , fmt = '%.6f' )
92+
93+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.txt' , delete = False ) as temp_test :
94+ np .savetxt (temp_test .name , test_data , fmt = '%.6f' )
95+
96+ try :
97+ # Override the plots directory to ensure it's saved in the correct location
98+ import sys as sys_module
99+ sys_module .path .append (os .path .join (os .path .dirname (__file__ ), '..' ))
100+ from compare_template import create_comparison_plot , format_path
101+
102+ # Manually create the comparison plot to control the output directory
103+ for config in test_configs :
104+ column_index = config ['column_index' ]
105+ test_name = config ['test_name' ]
106+ y_label = config ['y_label' ]
107+
108+ # Create data arrays for this column
109+ ref_col_data = np .column_stack ((ref_data_interp [:, 0 ], ref_data_interp [:, column_index ]))
110+ test_col_data = np .column_stack ((test_data [:, 0 ], test_data [:, column_index ]))
111+
112+ # Create the plot in the correct directory
113+ create_comparison_plot (
114+ ref_col_data , test_col_data , test_name , plots_dir ,
115+ ref_file_path = format_path (ref_file ),
116+ test_file_path = format_path (test_file ),
117+ y_label = y_label ,
118+ executable_patterns = executable_patterns
119+ )
120+
121+ # Create dummy results for compatibility
122+ results = [(0.0 , 0.0 , True )] * len (test_configs )
123+ finally :
124+ # Clean up temporary files
125+ os .unlink (temp_ref .name )
126+ os .unlink (temp_test .name )
127+
128+ # Additional RM3-specific validations
129+ nval = test_data .shape [0 ]
130+
131+ # Resample refData to testData sampling rate
132+ x = np .linspace (test_data [0 , 0 ], test_data [nval - 1 , 0 ], nval )
133+
134+ # Compare float heave
135+ floatHeaveRef = np .interp (x , ref_data [:,0 ], ref_data [:,1 ])
136+ floatHeaveTest = np .interp (x , test_data [:,0 ], test_data [:,1 ])
137+ floatHeaveComp = floatHeaveRef - floatHeaveTest
138+
139+ # Compare plate heave
140+ plateHeaveRef = np .interp (x , ref_data [:,0 ], ref_data [:,2 ])
141+ plateHeaveTest = np .interp (x , test_data [:,0 ], test_data [:,2 ])
142+ plateHeaveComp = plateHeaveRef - plateHeaveTest
143+
144+ # Compare float drift
145+ floatDriftRef = np .interp (x , ref_data [:,0 ], ref_data [:,3 ])
146+ floatDriftTest = np .interp (x , test_data [:,0 ], test_data [:,3 ])
147+ floatDriftComp = floatDriftRef - floatDriftTest
148+
149+ # Frobenius norm - Float Heave
150+ floatHeaven1 = np .linalg .norm (floatHeaveComp )/ nval
151+ # infinity norm - Float Heave
152+ floatHeaven2 = np .linalg .norm (floatHeaveComp , np .inf )
153+
154+ # Frobenius norm - Plate Heave
155+ plateHeaven1 = np .linalg .norm (plateHeaveComp )/ nval
156+ # infinity norm - Plate Heave
157+ plateHeaven2 = np .linalg .norm (plateHeaveComp , np .inf )
158+
159+ # Frobenius norm - Float Drift
160+ floatDriftn1 = np .linalg .norm (floatDriftComp )/ nval
161+ # infinity norm - Float Drift
162+ floatDriftn2 = np .linalg .norm (floatDriftComp , np .inf )
163+
164+ if (floatHeaven1 > 1e-4 or floatHeaven2 > 0.02 or
165+ plateHeaven1 > 1e-4 or plateHeaven2 > 0.02 or
166+ floatDriftn1 > 1e-4 or floatDriftn2 > 0.02 ):
167+ print (f"RM3 validation failed: Float heave difference { floatHeaven1 :.2e} > 1e-4 or { floatHeaven2 :.2e} > 0.02" )
168+ print (f"RM3 validation failed: Plate heave difference { plateHeaven1 :.2e} > 1e-4 or { plateHeaven2 :.2e} > 0.02" )
169+ print (f"RM3 validation failed: Float drift difference { floatDriftn1 :.2e} > 1e-4 or { floatDriftn2 :.2e} > 0.02" )
170+ sys .exit (1 )
171+
172+ # Check if all template comparisons passed
173+ all_passed = all (result [2 ] for result in results )
174+
175+ if all_passed :
176+ print ("RM3 REGULAR WAVES TEST PASSED - All comparisons within tolerance" )
177+ print (f"Generated plots:" )
178+ for config in test_configs :
179+ plot_name = config ['test_name' ].lower ().replace (' ' , '_' ).replace ('-' , '_' )
180+ print (f" - { config ['test_name' ]} : { plots_dir } /{ plot_name } _comparison.png" )
181+ else :
182+ print ("RM3 REGULAR WAVES TEST FAILED - Some comparisons outside tolerance" )
183+ sys .exit (1 )
184+
185+ except Exception as e :
186+ print (f"Error during comparison: { e } " )
187+ sys .exit (1 )
188+
189+ if __name__ == "__main__" :
190+ main ()
0 commit comments