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
a, b, c, aa, bb, cc = crystal.get_unit_cell().parameters()
aa *= DEG2RAD
bb *= DEG2RAD
cc *= DEG2RAD
Ut = crystal.get_U().transpose()
avec, bvec, cvec = [Ut * vec for vec in crystal.get_real_space_vectors()]

# calculate d[B^T]/dp
dB_dp = xluc_param.get_ds_dp()
dBT_dp = [dB.transpose() for dB in dB_dp]

# calculate d[O]/dp
dO_dp = [-O * dBT * O for dBT in dBT_dp]

# objects to get derivative of angles wrt vectors
dalpha = AngleDerivativeWrtVectorElts(bvec, cvec)
dbeta = AngleDerivativeWrtVectorElts(avec, cvec)
dgamma = AngleDerivativeWrtVectorElts(avec, bvec)

# get all FD derivatives
fd_grad = check_fd_gradients(xluc_param)

# look at each parameter
for i, dO in enumerate(dO_dp):

  print
  print "***** PARAMETER {0} *****".format(i)

  #print "dB_dp analytical"
  #print dB_dp[i]
  #print "dB_dp FD"