diff --git a/mhkit/types/cast/typecast_spectra_to_mhkit_python.m b/mhkit/types/cast/typecast_spectra_to_mhkit_python.m index 56fad12a..875fe731 100644 --- a/mhkit/types/cast/typecast_spectra_to_mhkit_python.m +++ b/mhkit/types/cast/typecast_spectra_to_mhkit_python.m @@ -1,69 +1,87 @@ function df = typecast_spectra_to_mhkit_python(S) - % Initialize empty python list for column names - column_names = py.list(); - % Validate frequency is 1D and make row-wise - freq_dims = size(S.frequency); - if length(freq_dims) > 2 || (freq_dims(1) ~= 1 && freq_dims(2) ~= 1) - error('Frequency must be a 1D array. Current dimensions are %s', mat2str(freq_dims)); - end - freq_length = length(S.frequency); - if freq_dims(1) ~= 1 - S.frequency = S.frequency(:)'; - end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% Typecast input spectra struct into a MHKiT-Python compatible +% pandas DataFrame. +% +% Parameters +% ---------- +% S : struct +% A structure containing: +% - frequency : (1D array) Frequency values (Hz) +% - spectrum : (1D or 2D matrix) Spectral density values (m^2/Hz) +% - type (optional) : (cell array of strings) Names for each spectrum column, +% e.g., 'JONSWAP', 'Pierson Moskowitz', etc. +% +% Returns +% ------- +% df : Python pandas.DataFrame +% A Pandas DataFrame with frequencies (Hz) as the index and +% spectral density values (m^2/Hz) as columns. Column names are either +% provided by S.type or automatically generated as 'spectrum_N'. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - % Get initial spectrum dimensions - [spec_rows, spec_cols] = size(S.spectrum); +% Initialize empty Python list for column names +column_names = py.list(); - % Case 1: Square matrix matching frequency length - if spec_rows == spec_cols && spec_rows == freq_length - warning('Input spectrum is square (%d×%d) and matches frequency length. Unable to determine orientation. Assuming input orientation is correct.', spec_rows, spec_cols); +% Validate that frequency is a 1D array and convert it to a row vector if needed +freq_dims = size(S.frequency); +if length(freq_dims) > 2 || (freq_dims(1) ~= 1 && freq_dims(2) ~= 1) + error('Frequency must be a 1D array. Current dimensions are %s', mat2str(freq_dims)); +end +freq_length = length(S.frequency); +if freq_dims(1) ~= 1 + S.frequency = S.frequency(:)'; % Ensure frequency is row-wise +end + +% Get initial spectrum dimensions +[spec_rows, spec_cols] = size(S.spectrum); - % Case 2: Already correct shape (rows match frequency length) - elseif spec_cols == freq_length - % No action needed, already correct +% Handle different spectrum shapes and orientations +if spec_rows == spec_cols && spec_rows == freq_length + % Case 1: Square matrix where rows = cols = frequency length + warning('Spectrum is square (%d×%d) and matches frequency length. Assuming input orientation is correct.', ... + spec_rows, spec_cols); +elseif spec_cols == freq_length + % Case 2: Spectrum already correctly shaped (rows = M, cols = frequency length) + % No transformation needed +elseif spec_rows == freq_length + % Case 3: Spectrum has incorrect orientation (transpose needed) + S.spectrum = S.spectrum'; + [spec_rows, spec_cols] = size(S.spectrum); +else + % Case 4: Invalid dimensions that cannot be reconciled + error('Spectrum dimensions (%d×%d) do not match frequency length (%d). Expected 1×%d or M×%d.', ... + spec_rows, spec_cols, freq_length, freq_length, freq_length); +end - % Case 3: Wrong orientation but can be fixed - elseif spec_rows == freq_length - S.spectrum = S.spectrum'; - [spec_rows, spec_cols] = size(S.spectrum); +% Convert frequency array to Python NumPy array for Pandas index +freq_index = py.numpy.array(S.frequency); - % Case 4: Invalid dimensions +% Convert spectrum data to NumPy array +if spec_rows == 1 + % Case: Single spectrum + spectrum_data = py.numpy.array(S.spectrum); + if isfield(S, 'type') + column_names.append(py.str(S.type)); % Use provided type as column name else - error('Spectrum dimensions (%d×%d) cannot be reconciled with frequency length (%d). Spectrum should be either 1×%d or M×%d.', ... - spec_rows, spec_cols, freq_length, freq_length, freq_length); + column_names.append(py.str('spectrum')); % Default column name end - - % Create the frequency index - freq_index = py.numpy.array(S.frequency); - - % Handle single or multiple spectra - if spec_rows == 1 - % Single spectrum case - spectrum_data = py.numpy.array(S.spectrum); - % Use type as column name, default to 'spectrum' if not provided - if isfield(S, 'type') - column_names.append(py.str(S.type)); +else + % Case: Multiple spectra + spectrum_data = py.numpy.zeros([spec_rows, spec_cols]); + for i = 1:spec_rows + spectrum_data(:, i) = py.numpy.array(S.spectrum(i, :)); % Convert each row + if isfield(S, 'type') && length(S.type) >= i + column_names.append(py.str(S.type{i})); % Use provided type name else - column_names.append(py.str('spectrum')); - end - else - % Multiple spectra case - % Convert all columns to numpy arrays and store column names - spectrum_data = py.numpy.zeros([spec_rows, spec_cols]); - for i = 1:spec_rows - spectrum_data(:,i) = py.numpy.array(S.spectrum(i,:)); - % Generate column name for each spectrum - if isfield(S, 'type') && length(S.type) >= i - column_names.append(py.str(S.type{i})); - else - column_names.append(py.str(sprintf('spectrum_%d', i))); - end + column_names.append(py.str(sprintf('spectrum_%d', i))); % Generate name end end - - % Create pandas DataFrame with frequency as index - df = py.pandas.DataFrame(data=spectrum_data, ... - index=freq_index, ... - columns=column_names); end + +% Create a Pandas DataFrame with frequency as the index +df = py.pandas.DataFrame(data=spectrum_data, ... + index=freq_index, ... + columns=column_names);