/* wavefunction.h -- compute atomic wavefunctions.  -*- C++ -*-
   Copyright (C) 2024, 2025 Gerardo Ballabio

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>. */

#include <string>

#ifndef __WAVEFUNCTION_
#define __WAVEFUNCTION_

// hydrogen-like atom
class wavefunction
{
private:
  static const double a0; // Bohr radius
  static const int nmax, lmax;
  unsigned z; // atomic number
  double z_a0, z_a0_32;
  int n, l, m; // quantum numbers
  double max;
  std::string label;

  // radial part of wavefunctions
  double (*rf)(double zr_a0);

  static double r_10(double zr_a0);

  static double r_20(double zr_a0);
  static double r_21(double zr_a0);

  static double r_30(double zr_a0);
  static double r_31(double zr_a0);
  static double r_32(double zr_a0);

  static double r_40(double zr_a0);
  static double r_41(double zr_a0);
  static double r_42(double zr_a0);
  static double r_43(double zr_a0);

  static double r_50(double zr_a0);
  static double r_51(double zr_a0);
  static double r_52(double zr_a0);
  static double r_53(double zr_a0);
  static double r_54(double zr_a0);

  static double r_60(double zr_a0);
  static double r_61(double zr_a0);
  static double r_62(double zr_a0);
  static double r_63(double zr_a0);
  static double r_64(double zr_a0);
  static double r_65(double zr_a0);

  static double r_70(double zr_a0);
  static double r_71(double zr_a0);
  static double r_72(double zr_a0);
  static double r_73(double zr_a0);
  static double r_74(double zr_a0);
  static double r_75(double zr_a0);
  static double r_76(double zr_a0);

  static double r_80(double zr_a0);
  static double r_81(double zr_a0);
  static double r_82(double zr_a0);
  static double r_83(double zr_a0);
  static double r_84(double zr_a0);
  static double r_85(double zr_a0);
  static double r_86(double zr_a0);

  static double r_90(double zr_a0);
  static double r_91(double zr_a0);
  static double r_92(double zr_a0);
  static double r_93(double zr_a0);
  static double r_94(double zr_a0);
  static double r_95(double zr_a0);
  static double r_96(double zr_a0);

  // angular part of wavefunctions (real spherical harmonics)
  double (*yf)(double x_r, double y_r, double z_r);

  static double y_00(double x_r, double y_r, double z_r);

  static double y_1m1(double x_r, double y_r, double z_r);
  static double y_10(double x_r, double y_r, double z_r);
  static double y_11(double x_r, double y_r, double z_r);

  static double y_2m2(double x_r, double y_r, double z_r);
  static double y_2m1(double x_r, double y_r, double z_r);
  static double y_20(double x_r, double y_r, double z_r);
  static double y_21(double x_r, double y_r, double z_r);
  static double y_22(double x_r, double y_r, double z_r);

  static double y_3m3(double x_r, double y_r, double z_r);
  static double y_3m2(double x_r, double y_r, double z_r);
  static double y_3m1(double x_r, double y_r, double z_r);
  static double y_30(double x_r, double y_r, double z_r);
  static double y_31(double x_r, double y_r, double z_r);
  static double y_32(double x_r, double y_r, double z_r);
  static double y_33(double x_r, double y_r, double z_r);

  static double y_4m4(double x_r, double y_r, double z_r);
  static double y_4m3(double x_r, double y_r, double z_r);
  static double y_4m2(double x_r, double y_r, double z_r);
  static double y_4m1(double x_r, double y_r, double z_r);
  static double y_40(double x_r, double y_r, double z_r);
  static double y_41(double x_r, double y_r, double z_r);
  static double y_42(double x_r, double y_r, double z_r);
  static double y_43(double x_r, double y_r, double z_r);
  static double y_44(double x_r, double y_r, double z_r);

  static double y_5m5(double x_r, double y_r, double z_r);
  static double y_5m4(double x_r, double y_r, double z_r);
  static double y_5m3(double x_r, double y_r, double z_r);
  static double y_5m2(double x_r, double y_r, double z_r);
  static double y_5m1(double x_r, double y_r, double z_r);
  static double y_50(double x_r, double y_r, double z_r);
  static double y_51(double x_r, double y_r, double z_r);
  static double y_52(double x_r, double y_r, double z_r);
  static double y_53(double x_r, double y_r, double z_r);
  static double y_54(double x_r, double y_r, double z_r);
  static double y_55(double x_r, double y_r, double z_r);

  static double y_6m6(double x_r, double y_r, double z_r);
  static double y_6m5(double x_r, double y_r, double z_r);
  static double y_6m4(double x_r, double y_r, double z_r);
  static double y_6m3(double x_r, double y_r, double z_r);
  static double y_6m2(double x_r, double y_r, double z_r);
  static double y_6m1(double x_r, double y_r, double z_r);
  static double y_60(double x_r, double y_r, double z_r);
  static double y_61(double x_r, double y_r, double z_r);
  static double y_62(double x_r, double y_r, double z_r);
  static double y_63(double x_r, double y_r, double z_r);
  static double y_64(double x_r, double y_r, double z_r);
  static double y_65(double x_r, double y_r, double z_r);
  static double y_66(double x_r, double y_r, double z_r);

public:
  wavefunction(unsigned z_ = 1);

  bool set_z(unsigned z_); // atomic number
  bool set(int n_, int l_, int m_); // quantum numbers

  const unsigned get_z() { return z; }
  const int get_n() { return n; }
  const int get_l() { return l; }
  const int get_m() { return m; }
  const std::string &get_label() { return label; }

  const int get_nmax() { return nmax; }
  const int get_lmax() { return lmax; }

  const double default_scale();
  const double default_vscale();
  const double max_wave(); // maximum absolute value

  // functions
  const double radial(double r); // radial part
  const double angular(double x_r, double y_r, double z_r); // angular part
  const double wave(double x, double y, double z); // full wavefunction
  const double density(double x, double y, double z); // probability density
};

#endif /* __WAVEFUNCTION_ */
