Repository: mir-group/flare_pp (language: python)

Issue:
TypeError at `gp_model.add_training_structure(train_struc)`
Thanks so much for your nice work, I tried to repeat the codes shown on Google Colab.
Everything works very well, until this step:
```
# Train the model.
print("Training the GP...") 
batch_size = 10  # monitor the MAE after adding this many frames
n_strucs = np.zeros(batch_size)
mb_maes = np.zeros(batch_size)
for m in range(training_size): # 100
  train_struc = training_strucs[m]

  # Add training structure and sparse environments.
  gp_model.add_training_structure(train_struc)
  gp_model.add_all_environments(train_struc)

  if (m + 1) % batch_size == 0: # 10 per iteration
    # Update the sparse GP training coefficients.
    gp_model.update_matrices_QR()

    # Predict on the validation set.
    pred_forces = np.zeros((validation_size, noa, 3))
    for n, test_struc in enumerate(validation_strucs):
      gp_model.predict_SOR(test_struc)
      pred_vals = test_struc.mean_efs[1:-6].reshape(noa, 3)
      pred_forces[n] = pred_vals
    
    # Calculate and store the MAE.
    batch_no = int((m + 1) / batch_size)
    mae = np.mean(np.abs(validation_forces - pred_forces))
    n_strucs[batch_no - 1] = batch_size * batch_no
    mb_maes[batch_no - 1] = mae
    print("Batch %i MAE: %.2f kcal/mol/A" % (batch_no, made))
```
Here is the error message.
```
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-10-c4db7c1083ef> in <module>
      8 
      9   # Add training structure and sparse environments.
---> 10   gp_model.add_training_structure(train_struc)
     11   gp_model.add_all_environments(train_struc)
     12 

TypeError: add_training_structure(): incompatible function arguments. The following argument types are supported:
    1. (self: flare_pp._C_flare.SparseGP, arg0: flare_pp._C_flare.Structure, arg1: List[int]) -> None

Invoked with: <flare_pp._C_flare.SparseGP object at 0x7ff6d426b130>, <flare_pp._C_flare.Structure object at 0x7ff6e16b7d70>
```
I actually didn't change any content, do you have ideas about the error?
PS: `pip install flare_pp` didn't work on my laptop, so I download your code from GitHub, then install manually. Fortunately, no error report while installation, and `flare_pp` also can be imported very well.
Thank you!



Discussion / hints:
Hi @mnTusi 

Thanks for your interest in our code! I think this issue is because of our recent update of code interface, that is not synced to the colab tutorial. We will address it soon.

Fix patch:
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 3ed343d3..c2653d84 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -115,3 +115,22 @@ jobs:
         export lmp="$(pwd)/lammps/build/lmp -k on t 4 -sf kk -pk kokkos newton on neigh full"
         cd tests
         pytest test_lammps.py
+
+    - name: Run tutorial
+      run: |
+        cd tests
+        # Download colab notebook
+        export fileid="18_pTcWM19AUiksaRyCgg9BCpVyw744xv"
+        wget -O tutorial.ipynb 'https://docs.google.com/uc?export=download&id='${fileid}
+        # Convert notebook into python script
+        jupyter nbconvert --to script tutorial.ipynb
+        # Remove bash commands in the notebook
+        sed '/!/d' tutorial.txt > tutorial.py
+        cat test_tutorial.py tutorial.py > tuttest.py
+        # Download datasets needed for the tutorial
+        wget http://quantum-machine.org/gdml/data/npz/aspirin_dft.npz
+        wget https://www.ctcms.nist.gov/potentials/Download/1999--Mishin-Y-Farkas-D-Mehl-M-J-Papaconstantopoulos-D-A--Al/2/Al99.eam.alloy
+        # Run script
+        pytest -s tuttest.py
+        # Remove output files
+        rm Al* aspirin_dft.npz tutorial.ipynb tuttest.py tutorial.py tutorial.txt
diff --git a/requirements.txt b/requirements.txt
index ff2ec781..fb048a67 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,4 @@
 cmake>=3.14.5
 mir-flare
+jupyter
+nbconvert
diff --git a/src/ace_binding.cpp b/src/ace_binding.cpp
index 158becda..ea5802fd 100644
--- a/src/ace_binding.cpp
+++ b/src/ace_binding.cpp
@@ -139,7 +139,7 @@ PYBIND11_MODULE(_C_flare, m) {
   py::class_<NormalizedDotProduct, Kernel>(m, "NormalizedDotProduct")
       .def(py::init<double, double>())
       .def_readonly("sigma", &NormalizedDotProduct::sigma)
-      .def_readonly("power", &NormalizedDotProduct::power)
+      .def_readwrite("power", &NormalizedDotProduct::power)
       .def_readonly("kernel_hyperparameters",
                     &NormalizedDotProduct::kernel_hyperparameters)
       .def("envs_envs", &NormalizedDotProduct::envs_envs)
@@ -167,7 +167,9 @@ PYBIND11_MODULE(_C_flare, m) {
       .def("add_random_environments", &SparseGP::add_random_environments)
       .def("add_uncertain_environments",
            &SparseGP::add_uncertain_environments)
-      .def("add_training_structure", &SparseGP::add_training_structure)
+      .def("add_training_structure", &SparseGP::add_training_structure,
+                       py::arg("structure"),
+                       py::arg("atom_indices") = - Eigen::VectorXi::Ones(1))
       .def("update_matrices_QR", &SparseGP::update_matrices_QR)
       .def("compute_likelihood", &SparseGP::compute_likelihood)
       .def("compute_likelihood_stable", &SparseGP::compute_likelihood_stable)
diff --git a/src/flare_pp/kernels/normalized_dot_product.cpp b/src/flare_pp/kernels/normalized_dot_product.cpp
index 6d0ac635..a6120cde 100644
--- a/src/flare_pp/kernels/normalized_dot_product.cpp
+++ b/src/flare_pp/kernels/normalized_dot_product.cpp
@@ -838,7 +838,7 @@ Eigen::MatrixXd NormalizedDotProduct ::compute_varmap_coefficients(
 }
 
 void NormalizedDotProduct ::write_info(std::ofstream &coeff_file) {
-  coeff_file << std::fixed << std::setprecision(1);
+  coeff_file << std::fixed << std::setprecision(0);
   coeff_file << power << "\n";
 }
 


Test patch:
diff --git a/tests/get_sgp.py b/tests/get_sgp.py
index 63c54672..c92cc875 100644
--- a/tests/get_sgp.py
+++ b/tests/get_sgp.py
@@ -9,7 +9,7 @@
 
 # Define kernel.
 sigma = 2.0
-power = 1
+power = 1.0
 kernel = NormalizedDotProduct(sigma, power)
 
 # Define B2 calculator.
@@ -52,9 +52,7 @@ def get_random_atoms(a=2.0, sc_size=2, numbers=[6, 8],
 
 
 def get_empty_sgp(n_types=2, power=2):
-#    # Define kernel.
-#    sigma = 2.0
-#    kernel = NormalizedDotProduct(sigma, power)
+    kernel.power = power
 
     descriptor_settings = [n_types, 8, 3]
     b2_calc = B2(radial_basis, cutoff_function, radial_hyps, cutoff_hyps,
diff --git a/tests/test_lammps.py b/tests/test_lammps.py
index bc5817a6..be857da7 100644
--- a/tests/test_lammps.py
+++ b/tests/test_lammps.py
@@ -10,7 +10,7 @@
 
 n_species_list = [1, 2]
 n_desc_types = [1, 2]
-power_list = [1] #, 2]
+power_list = [1, 2]
 rootdir = os.getcwd()
 
 @pytest.mark.skipif(
@@ -34,7 +34,7 @@ def test_write_potential(n_species, n_types, power):
 
     # Write potential file.
     sgp_model = get_sgp_calc(n_types, power)
-    potential_name = f"LJ_{n_species}_{n_types}.txt"
+    potential_name = f"LJ_{n_species}_{n_types}_{power}.txt"
     contributor = "Jon"
     kernel_index = 0
     sgp_model.gp_model.sparse_gp.write_mapping_coefficients(
@@ -114,7 +114,7 @@ def test_lammps_uncertainty(n_species, n_types, use_map, power):
     contributor = "YX"
     kernel_index = 0
 
-    potential_file = f"LJ_{n_species}_{n_types}.txt"
+    potential_file = f"LJ_{n_species}_{n_types}_{power}.txt"
     sgp_model.gp_model.write_mapping_coefficients(
         potential_file, contributor, kernel_index)
 
diff --git a/tests/test_tutorial.py b/tests/test_tutorial.py
new file mode 100644
index 00000000..4da76c1c
--- /dev/null
+++ b/tests/test_tutorial.py
@@ -0,0 +1,7 @@
+import pytest
+
+def test_tutorial():
+    """
+    This function is to prevent a dry run without test
+    """
+    return