Skip to content

visualdynamics.io.sdynpy_data

sdynpy_data

Read and write sdynpy data array files (.npz).

The format is a NumPy .npz with two entries:

  • 'function_type': a scalar int, the universal file dataset 58 function type code, which is the vocabulary Visual Dynamics uses (1 time response, 4 FRF, 6 coherence, 9 PSD, 12 spectrum and so on).
  • 'data': a structured array of records with the fields 'abscissa' (n,), 'ordinate' (n,), 'comment1' to 'comment5', and 'coordinate', the (node, direction) pairs, shape (1,) for data with a response only or (2,) for response and reference. Directions use the signed universal file code, 1 to 6.

The files have no units. Units may be declared at import:

  • time and spectrum data: ordinate_unit (for example 'm/s**2', 'g' or 'N');
  • FRFs: response_unit and reference_unit, both needed;
  • PSDs: ordinate_unit, the unit whose square per Hz the PSD is in (for example 'g' for g^2/Hz).

Without them the data is unit-less, holding the file's values, and the units can be defined later with define_units(). Every record must share one abscissa; a file whose records differ is refused.

Functions:

Name Description
save

Write a data array in the sdynpy .npz layout.

Classes

Functions:

save

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

Write a data array in the sdynpy .npz layout.

Values are written in the coherent form of unit_system when the units are defined, and as stored otherwise. The format has no place to record which units they are. The ordinate is complex only when the data is, and the comment fields are left blank.

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 the sdynpy .npz layout.

    Values are written in the coherent form of `unit_system` when the
    units are defined, and as stored otherwise. The format has no place
    to record which units they are. The ordinate is complex only when
    the data is, and the comment fields are left blank.
    """
    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))