function cmp = mfs_freevib(cmp, nmodes, options)

# usage: cmp = mfs_freevib(cmp, nmodes, options)
#
# Input  cmp     Structure with component data
#        nmodes  Number of modes to compute
#        options Structure with options
#
# Output cmp     Structure with component data 
#                (displacement matrix added)
#
# The function computes the free vibration modes of a component. The
# normal modes a normalized with respect to the mass matrix.
#
# Options:
#
#   rbc          Rigid body criterion: z = 10^rbc * eps
#                Default: 6
#   rdofs(:, 2)  Definition of rigid body dofs
#   disp         passed to eigs
#   maxit        passed to eigs
#   p            passed to eigs
#   tol          passed to eigs
#
# ---------------------------------------------------------------------

# Copyright (c) 2022 by Johannes Wandinger

  t0 = clock();

# Default options

  opts = struct("rbc", 6);

# Check arguments

  if (nargin < 2 || nargin > 3 || nargout != 1)
     print_usage();
  end
  if (! isstruct(cmp))
     error("mfs_freevib: first argument must be a structure\n");
  end
  if (! isscalar(nmodes) || nmodes <= 0)
     error("mfs_freevib: second argument must be a positive scalar\n");
  end

# Branch on component type

  switch cmp.type

  case "solid"
     time_stamp = ignore_function_time_stamp("all");
     if (nargin == 2)
        options = opts;
     else
        options = mfs_defopts(options, opts);
     end
     mfs_paths("add", "mfs_freevib.m", "solid", "util");
     [cmp, rc] = mfs_freevibx(cmp, nmodes, options);
     mfs_paths("remove");
     ignore_function_time_stamp(time_stamp);
  otherwise
     error("mfs_freevib: component type \"%s\" not supported\n",
           cmp.type);
  end

  if (rc)
     error("mfs_freevib ended with errors\n");
  end

  elapsed_time = etime(clock(), t0);
  printf("%10.4f seconds needed to compute %4d normal modes of component %s\n", ...
         elapsed_time, nmodes, inputname(1));
  fflush(stdout);

end
