Repository: sympy/sympy

Issue:
bug in physics/mechanics/lagrange.py
When providing a `forcelist` with more than one force, not all terms are computed,
this comes from the fact that the iterator `flist = zip(*_f_list_parser(self.forcelist, N))` is consumed in the first iteration of the loop.

I propose a following PR that fixes the bug, let me know if I need to also provide a test case.

Best,
Guillaume

Discussion:
glyg: bumb?

Is this ok? I'd like to go back to using master...
jcrist: Please look at how other tests are written in sympy. Tests should be enclosed in their own function. For example, see the [existing tests for lagrange](https://github.com/sympy/sympy/blob/master/sympy/physics/mechanics/tests/test_lagrange.py).
glyg: is it ok like that, or are the `assert` statements too dumb?
jcrist: If they thoroughly test the issue you're fixing, then they're fine. If you could fix my two inline comments, and then squash your commits, this is good to go.


Patch:
diff --git a/sympy/physics/mechanics/lagrange.py b/sympy/physics/mechanics/lagrange.py
index 7e90313170..5206d7687e 100644
--- a/sympy/physics/mechanics/lagrange.py
+++ b/sympy/physics/mechanics/lagrange.py
@@ -210,10 +210,9 @@ def form_lagranges_equations(self):
         if self.forcelist:
             N = self.inertial
             self._term4 = zeros(n, 1)
-            flist = zip(*_f_list_parser(self.forcelist, N))
             for i, qd in enumerate(qds):
-                for obj, force in self.forcelist:
-                    self._term4[i] = sum(v.diff(qd, N) & f for (v, f) in flist)
+                flist = zip(*_f_list_parser(self.forcelist, N))
+                self._term4[i] = sum(v.diff(qd, N) & f for (v, f) in flist)
         else:
             self._term4 = zeros(n, 1)
 


Test patch:
diff --git a/sympy/physics/mechanics/tests/test_lagrange2.py b/sympy/physics/mechanics/tests/test_lagrange2.py
new file mode 100644
index 0000000000..2b2cca808a
--- /dev/null
+++ b/sympy/physics/mechanics/tests/test_lagrange2.py
@@ -0,0 +1,46 @@
+from sympy import symbols
+from sympy.physics.mechanics import dynamicsymbols
+from sympy.physics.mechanics import ReferenceFrame, Point, Particle
+from sympy.physics.mechanics import LagrangesMethod, Lagrangian
+
+### This test asserts that a system with more than one external forces
+### is acurately formed with Lagrange method (see issue #8626)
+
+def test_lagrange_2forces():
+    ### Equations for two damped springs in serie with two forces
+
+    ### generalized coordinates
+    qs = q1, q2 = dynamicsymbols('q1, q2')
+    ### generalized speeds
+    qds = q1d, q2d = dynamicsymbols('q1, q2', 1)
+
+    ### Mass, spring strength, friction coefficient
+    m, k, nu = symbols('m, k, nu')
+
+    N = ReferenceFrame('N')
+    O = Point('O')
+
+    ### Two points
+    P1 = O.locatenew('P1', q1 * N.x)
+    P1.set_vel(N, q1d * N.x)
+    P2 = O.locatenew('P1', q2 * N.x)
+    P2.set_vel(N, q2d * N.x)
+
+    pP1 = Particle('pP1', P1, m)
+    pP1.set_potential_energy(k * q1**2 / 2)
+
+    pP2 = Particle('pP2', P2, m)
+    pP2.set_potential_energy(k * (q1 - q2)**2 / 2)
+
+    #### Friction forces
+    forcelist = [(P1, - nu * q1d * N.x),
+                 (P2, - nu * q2d * N.x)]
+    lag = Lagrangian(N, pP1, pP2)
+
+    l_method = LagrangesMethod(lag, (q1, q2), forcelist=forcelist, frame=N)
+    l_method.form_lagranges_equations()
+
+    eq1 = l_method.eom[0]
+    assert eq1.diff(q1d) == nu
+    eq2 = l_method.eom[1]
+    assert eq2.diff(q2d) == nu