def test():

  # Two random vectors
  vec_a = matrix.col((uniform(-20,20), uniform(-20,20), uniform(-20,20)))
  vec_b = matrix.col((uniform(-20,20), uniform(-20,20), uniform(-20,20)))

  # The test may fail if the angle between the vectors is small or close to pi
  # (see gradient of acos(x) for x close to 1 or -1) but we are not interested
  # in such cases anyway. Skip test if the acute angle is less than 1 degree
  if vec_a.accute_angle(vec_b, deg=True) < 1: return False

  a = vec_a.length()
  b = vec_b.length()
  a_dot_b = vec_a.dot(vec_b)
  gamma = acos(a_dot_b / (a*b))

  # Analytical
  dg = AngleDerivativeWrtVectorElts(vec_a, vec_b)

  # FD
  dgFD = FDAngleDerivativeWrtVectorElts(vec_a, vec_b)
  assert approx_equal(dg.dtheta_du_1(), dgFD.dtheta_du_1())
  assert approx_equal(dg.dtheta_du_2(), dgFD.dtheta_du_2())
  assert approx_equal(dg.dtheta_du_3(), dgFD.dtheta_du_3())
  assert approx_equal(dg.dtheta_dv_1(), dgFD.dtheta_dv_1())
  assert approx_equal(dg.dtheta_dv_2(), dgFD.dtheta_dv_2())
  assert approx_equal(dg.dtheta_dv_3(), dgFD.dtheta_dv_3())

  # Test vector version
  assert approx_equal(dg.derivative_wrt_u(), matrix.col(
    (dg.dtheta_du_1(), dg.dtheta_du_2(), dg.dtheta_du_3())))
  assert approx_equal(dg.derivative_wrt_v(), matrix.col(
    (dg.dtheta_dv_1(), dg.dtheta_dv_2(), dg.dtheta_dv_3())))

  return True
  print "d[a]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(da_dp, fd_grad[i]['da_dp'], i)

  db_dp = 1./b * bvec.dot(dbv_dp)
  print "d[b]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(db_dp, fd_grad[i]['db_dp'], i)

  dc_dp = 1./c * cvec.dot(dcv_dp)
  print "d[c]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(dc_dp, fd_grad[i]['dc_dp'], i)

  print
  print "CELL ANGLES"

  # Here we know the derivatives of the angle alpha with respect to elements
  # of the vectors a and b. Similarly for beta and gamma. We know these
  # expressions are correct because they are tested in
  # tst_angle_derivatives_wrt_vector_elts.py
  dalpha_db = dalpha.derivative_wrt_u()
  dalpha_dc = dalpha.derivative_wrt_v()
  dbeta_da = dbeta.derivative_wrt_u()
  dbeta_dc = dbeta.derivative_wrt_v()
  dgamma_da = dgamma.derivative_wrt_u()
  dgamma_db = dgamma.derivative_wrt_v()

  #
  daa_dp = RAD2DEG * (dbv_dp.dot(dalpha_db) + dcv_dp.dot(dalpha_dc))
  dbb_dp = RAD2DEG * (dav_dp.dot(dbeta_da) + dcv_dp.dot(dbeta_dc))
  dcc_dp = RAD2DEG * (dav_dp.dot(dgamma_da) + dbv_dp.dot(dgamma_db))

  print "d[alpha]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(daa_dp, fd_grad[i]['daa_dp'], i)
  print "d[beta]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(dbb_dp, fd_grad[i]['dbb_dp'], i)
  print "d[gamma]/dp{2} analytical: {0:.5f} FD: {1:.5f}".format(dcc_dp, fd_grad[i]['dcc_dp'], i)