code: def transform(name, X, Y, *, g_correct=None, recursive=False):
      """
      Transforms from cartesian coordinates X to any curvilinear coordinates Y.
  
      It printing useful information, like Jacobian, metric tensor, determinant
      of metric, Laplace operator in the new coordinates, ...
  
      g_correct ... if not None, it will be taken as the metric --- this is
                    useful if sympy's trigsimp() is not powerful enough to
                    simplify the metric so that it is usable for later
                    calculation. Leave it as None, only if the metric that
                    transform() prints is not simplified, you can help it by
                    specifying the correct one.
  
      recursive ... apply recursive trigonometric simplification (use only when
                    needed, as it is an expensive operation)
      """
      print("_" * 80)
      print("Transformation:", name)
      for x, y in zip(X, Y):
          pprint(Eq(y, x))
      J = X.jacobian(Y)
      print("Jacobian:")
      pprint(J)
      g = J.T * eye(J.shape[0]) * J
  
      g = g.applyfunc(expand)
      print("metric tensor g_{ij}:")
      pprint(g)
      if g_correct is not None:
          g = g_correct
          print("metric tensor g_{ij} specified by hand:")
          pprint(g)
      print("inverse metric tensor g^{ij}:")
      g_inv = g.inv(method="ADJ")
      g_inv = g_inv.applyfunc(simplify)
      pprint(g_inv)
      print("det g_{ij}:")
      g_det = g.det()
      pprint(g_det)
      f = Function("f")(*list(Y))
      print("Laplace:")
      pprint(laplace(f, g_inv, g_det, Y))
  
imports: from sympy import var, sin, cos, pprint, Matrix, eye, trigsimp, Eq, Function, simplify, sinh, cosh, expand, symbols
label_desc: Use image node_id 2 for calling a global function with example usage: transform(name, X, Y) without return types