double hydrogenAtomPsiAt(Point3f pt, int n, int el, int m) {
		// ref: http://www.stolaf.edu/people/hansonr/imt/concept/schroed.pdf
		int abm = Math.abs(m);
		double x2y2 = pt.x * pt.x + pt.y * pt.y;
		double r2 = x2y2 + pt.z * pt.z;
		double r = Math.sqrt(r2);
		double rho = 2d * psi_Znuc * r / n / A0;
		double ph, th, cth, sth;
		double theta_lm = 0;
		double phi_m = 0;
		double sum = 0;
		for (int p = 0; p <= n - el - 1; p++)
			sum += Math.pow(-rho, p) * rfactor[p];
		double rnl = Math.exp(-rho / 2) * Math.pow(rho, el) * sum;
		ph = Math.atan2(pt.y, pt.x);
		th = Math.atan2(Math.sqrt(x2y2), pt.z);
		cth = Math.cos(th);
		sth = Math.sin(th);
		sum = 0;
		for (int p = abm; p <= el; p++)
			sum += Math.pow(1 + cth, p - abm) * Math.pow(1 - cth, el - p) * pfactor[p];
		theta_lm = Math.abs(Math.pow(sth, abm)) * sum;
		if (m == 0)
			phi_m = 1;
		else if (m > 0)
			phi_m = Math.cos(m * ph) * ROOT2;
		else phi_m = Math.sin(-m * ph) * ROOT2;
		if (Math.abs(phi_m) < 0.0000000001)
			phi_m = 0;
		return rnl * theta_lm * phi_m;
	}