Skip to content

Commit

Permalink
Types: Improve typecast_spectra_to_mhkit_python documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
simmsa committed Jan 31, 2025
1 parent eeeb28d commit d300601
Showing 1 changed file with 74 additions and 56 deletions.
130 changes: 74 additions & 56 deletions mhkit/types/cast/typecast_spectra_to_mhkit_python.m
Original file line number Diff line number Diff line change
@@ -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);

0 comments on commit d300601

Please sign in to comment.