Repository: fitbenchmarking/fitbenchmarking

Issue:
Hellinger nlls cost function -- Jacobian incorrect?
It seems like the Jacobian for the Hellinger nlls cost function is incorrect.  If we have 
![image](https://user-images.githubusercontent.com/13645545/125819226-0830cdbd-faa9-446e-9c9b-b3cb8275b446.png)
with Jacobian 
![image](https://user-images.githubusercontent.com/13645545/125819390-d3501792-3a3e-49b5-98ac-b93b2db8498b.png)
then for the Hellinger residual:
![image](https://user-images.githubusercontent.com/13645545/125819558-7395ff05-6bd6-473c-83df-493203cdcef9.png)
we should have 
![image](https://user-images.githubusercontent.com/13645545/125819913-517af1b1-b85d-4bd5-8097-ee7ce05e19e2.png)
However, the code actually calculates:
https://github.com/fitbenchmarking/fitbenchmarking/blob/c35a839af9dc75807c452ebcf2346c18fb4ce558/fitbenchmarking/jacobian/analytic_jacobian.py#L39-L41

This presumably explains the difference between accuracy in `scipy:2-point` and `analytic` Jacobian seen here:
![image](https://user-images.githubusercontent.com/13645545/125822165-a19fa6f4-7244-4a21-908f-d7a3767351b3.png)



Discussion:

Patch:
diff --git a/fitbenchmarking/jacobian/analytic_jacobian.py b/fitbenchmarking/jacobian/analytic_jacobian.py
index f2a62312..e0d3a135 100644
--- a/fitbenchmarking/jacobian/analytic_jacobian.py
+++ b/fitbenchmarking/jacobian/analytic_jacobian.py
@@ -2,6 +2,7 @@
 Module which acts as a analytic Jacobian calculator
 """
 from numpy import matmul
+from numpy import sqrt
 
 from fitbenchmarking.jacobian.base_jacobian import Jacobian
 from fitbenchmarking.utils.exceptions import NoJacobianError
@@ -38,7 +39,7 @@ class Analytic(Jacobian):
             jac = jac / e[:, None]
         elif self.problem.options.cost_func_type == "hellinger_nlls":
             # calculates the Jacobian of the hellinger(root) NLLS cost function
-            jac = jac * self.problem.eval_model(params, x=x)[:, None] / 2
+            jac = jac/(2*sqrt(self.problem.eval_model(params, x=x)[:, None]))
         elif self.problem.options.cost_func_type == "poisson":
             jac = jac * (1 - y / self.problem.eval_model(params, x=x))[:, None]
         return jac


Test patch:
diff --git a/fitbenchmarking/jacobian/tests/test_jacobian.py b/fitbenchmarking/jacobian/tests/test_jacobian.py
index f2561893..c69206ac 100644
--- a/fitbenchmarking/jacobian/tests/test_jacobian.py
+++ b/fitbenchmarking/jacobian/tests/test_jacobian.py
@@ -150,8 +150,8 @@ class TestJacobianClass(TestCase):
         jac = Analytic(self.cost_func)
         eval_result = jac.eval(params=self.params)
         #  pylint: disable=unsubscriptable-object
-        scaled_actual = self.actual * \
-            f(self.fitting_problem.data_x, *self.params)[:, None] / 2
+        scaled_actual = self.actual / \
+            (2*np.sqrt(f(self.fitting_problem.data_x, *self.params)[:, None]))
 
         self.assertTrue(np.isclose(scaled_actual, eval_result).all())