Skip to content

visualdynamics.io.sdynpy_data

sdynpy_data

Importer for sdynpy data array files (.npz).

The format is a numpy .npz with two entries:

  • 'function_type': scalar int, UFF dataset 58 function type code (the same vocabulary visualdynamics uses: 1 time response, 4 FRF, 9 PSD, 12 spectrum)
  • 'data': structured array with per-record fields 'abscissa' (n,), 'ordinate' (n,), 'comment1'..'comment5', and 'coordinate' — (node, direction) pairs, shape (1,) for response-only data or (2,) for response/reference data. Directions use the UFF signed 1..6 code.

Files carry no units. Units may be declared at import:

  • time/spectrum data: ordinate_unit (e.g. 'm/s**2', 'g', 'N')
  • FRF: response_unit and reference_unit
  • PSD: ordinate_unit = the engineering unit whose square- per-Hz the PSD is in (e.g. 'g' for g^2/Hz)

Without them the data arrives unit-less, holding the file's raw values, for the user to define units later with define_units().

Functions:

Name Description
save

Write a data array in sdynpy's own .npz layout.

Classes

Functions:

save

save(
    data: DataArray,
    path: str | PathLike,
    unit_system: UnitSystem | None = None,
) -> None

Write a data array in sdynpy's own .npz layout.

Values go out in unit_system, or as stored without one. The format has nowhere to record which units they are.

Source code in src/visualdynamics/io/sdynpy_data.py
def save(data: DataArray, path: str | os.PathLike, unit_system: UnitSystem | None = None) -> None:
    """Write a data array in sdynpy's own .npz layout.

    Values go out in `unit_system`, or as stored without one. The format
    has nowhere to record which units they are.
    """
    from .exporters import data_values

    abscissa, ordinate = data_values(data, unit_system)
    samples = len(abscissa)
    # complex only for data that is: a real time history written as
    # '<c16' doubles the file and comes back through the constructor
    # with a ComplexWarning, which is sdynpy's own convention anyway —
    # its writer stores each array in the ordinate's true dtype
    dtype = [('abscissa', '<f8', (samples,)),
             ('ordinate',
              '<c16' if np.iscomplexobj(ordinate) else '<f8', (samples,)),
             *[(f'comment{i}', '<U80') for i in range(1, 6)],
             ('coordinate', [('node', '<u8'), ('direction', 'i1')],
              (2 if data.reference_dof is not None else 1,))]
    records = np.zeros(data.num_records, dtype=dtype)
    records['abscissa'] = abscissa
    records['ordinate'] = ordinate
    records['coordinate'] = _coordinate_pairs(data)
    np.savez(path, data=records,
             function_type=np.array(data.function_type))