0

So I am trying to plot a graph of 3 of my functions for a beam on one graph using the matplotlib module and am getting value errors when attempting to do so. The main bulk of code is:

class beam(object):
    '''This class is models the deflection of a simply supported beam under
    multiple point loads, following Euler-Bernoulli theory and the principle      
    of superposition
    '''


    def __init__(self, E, I, L):
        '''The class costructor
        '''
        self.E = E  # Young's modulus of the beam in N/m^2
        self.I = I  # Second moment of area of the beam in m^4
        self.L = L  # Length of the beam in m
        self.Loads = [(0.0, 0.0)]  # the list of loads applied to the beam

    def setLoads(self, Loads):
        '''This function allows multiple point loads to be applied to the beam
        using a list of tuples of the form (load, position)
        '''
        self.Loads = Loads

    def beamDeflection(self, Load, x):
        """Calculate the deflection at point x due to application of single
        load
        """
        Force, distanceA = Load  #P1 = Force , a = distanceA
        E = self.E
        I = self.I
        L = self.L
        distanceB = L - distanceA
        i = (Force*distanceB)/(6*L*E*I)
        j = ((L/distanceB)*(x-distanceA)**3 - x**3 + (L**2 - distanceB**2)*x)
        k = (Force*distanceB*x)/(6*L*E*I)        
        l = (L**2 - x**2 - distanceB**2)
        if x > distanceA:
            return i*j
        else:
            return k*l


    def getTotalDeflection(self, x):
        """Calculate total deflection of beam due to multiple loads
        """
        #return sum(self.beamDeflection(loadall, x) for loadall in self.Loads)
        return sum(self.beamDeflection(load, x) for load in self.Loads)


    def getSlope(self, x):
        """Calculate gradient at a point x on beam due to deflection
        """
        V = lambda x: self.getTotalDeflection(x)
        return scipy.misc.derivative(V, x, dx = 10**-6)


    def getMoment(self, x):
        """Calculate bending moment at a point x on beam
        """
        E = self.E
        I = self.I
        W1 = lambda x: self.getSlope(x)
        W2 = scipy.misc.derivative(W1, x, dx = 10**-6)
        return (-1*E*I)*W2


    def plotBeamData(self, xs):
        """Plot deflection, slope and bending moment against position x for a
        list of floats or numpy.array xs describing positions along beam
        """
        deflection = self.getTotalDeflection(xs)
        slope = self.getSlope(xs)
        moment = self.getMoment(xs)    
        matplotlib.pyplot.plot(xs, deflection, 'b', label = "deflection (mm)")
        matplotlib.pyplot.plot(xs, slope, 'g', label = "slope (mm/m)")
        matplotlib.pyplot.plot(xs, moment, 'r', label = "moment (kNm)")
        matplotlib.pyplot.xlabel("Distance along beam (m)")
        matplotlib.pyplot.ylabel("Value in units")
        matplotlib.pyplot.show()

This is the section of code from the class shown above, I am getting an error when trying to run:

def plotBeamData(self, xs):
   ...

An example input would be:

>>> b = beam(8.0E9, 1.333E-4, 5.0)
>>> b.setLoads([(900, 3.1), (700, 3.8), (1000, 4.2)])
>>> xs = numpy.linspace(0,5,500)
>>> b.plotBeamData(xs)

The error I am receiving is:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:/Users/Dag/Downloads/beamModel.py", line 93, in plotBeamData
deflection = self.getTotalDeflection(xs)
  File "C:/Users/Dag/Downloads/beamModel.py", line 60, in getTotalDeflection
return sum(self.beamDeflection(load, x) for load in self.Loads)
  File "C:/Users/Dag/Downloads/beamModel.py", line 60, in <genexpr>
return sum(self.beamDeflection(load, x) for load in self.Loads)
  File "C:/Users/Dag/Downloads/beamModel.py", line 50, in beamDeflection
if x > distanceA:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

I had previously just changed the code changing it from deflection = self.getTotalDeflection, which was giving me a value error about x and y must be in the same dimension, to deflection = self.getTotalDeflection(xs) which is now giving me a new error. Grateful for any help, really stuck. Thanks.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
Student1001
  • 43
  • 1
  • 2
  • 7
  • The error is saying that either `x` or `distanceA` is an array with multiple values. And in this `if` statement only one value is allowed. – hpaulj Jan 02 '16 at 12:22
  • So how do I solve the issue? – Student1001 Jan 02 '16 at 15:55
  • Do you understand how the answer addresses this issue? If not I'd suggest playing around with smaller examples. I have to have an interpretive Python shell running even when editing a different script. I need to test pieces. – hpaulj Jan 02 '16 at 17:03

1 Answers1

3

beamDeflection works for a single x:

def beamDeflection(self, Load, x):
    """Calculate the deflection at point x due to application of single
    load"""

but you supply an array of xs:

def plotBeamData(self, xs):
    """Plot deflection, slope and bending moment against position x for a
    list of floats or numpy.array xs describing positions along beam
    """
    deflection = self.getTotalDeflection(xs)
    slope = self.getSlope(xs)
    moment = self.getMoment(xs)  

Change to:

def plotBeamData(self, xs):
    """Plot deflection, slope and bending moment against position x for a
    list of floats or numpy.array xs describing positions along beam
    """
    deflection = [self.getTotalDeflection(x) for x in xs]
    slope = [self.getSlope(x) for x in xs]
    moment = [self.getMoment(x) for x in xs]

and it works:

enter image description here

Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • Thank you so much. However, I don't understand why: 1. the getMoment and getSlope values are coming up as 0 despite my function returning different values and 2. the sensitivity of the graph being so low despite using numpy.linspace(0, 5, 500) which should give me values at 500 intervals. Sorry to hassle you, really appreciate the help. – Student1001 Jan 02 '16 at 16:05