New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for composite beams #14773

Merged
merged 13 commits into from Jun 19, 2018

Conversation

Projects
None yet
4 participants
@jashan498
Contributor

jashan498 commented Jun 4, 2018

Brief description of what is fixed or changed

This PR implements support for beams with variable second moment (or width). To represent a changing second_moment, we have to input it as a Piecewise function.
another_beam

So for the above beam second_moment would be Piecewise((I, x<=2), (2*I, x<=6), (I, x<=8)).

Other comments

Source used for the test cases. Have a look @parsoyaarihant @moorepants

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 4, 2018

Is the test case failing due to floats like 0.666666666666667 in the Piecewise? I cross-checked, answer is correct.

E = Symbol('E')
I = Symbol('I')
b = Beam(4, E, Piecewise((1.5*I,x<=2), (I, x<=4)))

This comment has been minimized.

@moorepants

moorepants Jun 5, 2018

Member

Why can't singularity functions handle this? Not clear why Piecewise is needed at all.

Can't there be something like: 10*<x-4>**2 / E1 / I1 + 5 * <x-10>**2 / E2 / I1?

Singularity Functions are just another way to express piecewise.

This comment has been minimized.

@jashan498

jashan498 Jun 5, 2018

Contributor

It was just that integration was simpler with Piecewise but it can be done the other way.
So the newer way to input variable second_moment is as a list of tuples of the form (Value, start, order, end). (similar to the way we input load)

@parsoyaarihant

This comment has been minimized.

Contributor

parsoyaarihant commented Jun 5, 2018

Should we add support for variable I along the length?

assert b.second_moment == 1.5*I*SingularityFunction(x, 0, 0) - 0.5*I*SingularityFunction(x, 2, 0) - I*SingularityFunction(x, 4, 0)
assert b.slope().subs(x, 4) == 120.0/(E*I)
assert b.slope().subs(x, 2) == 80.0/(E*I)
assert int(b.deflection().subs(x, 4).args[0]) == 302 # Coefficient of 1/(E*I)

This comment has been minimized.

@jashan498

jashan498 Jun 5, 2018

Contributor

b.deflection().subs(x, 4) is equal to 302.222222222222/(E*I) but due to 302.222222222222, assertion is failing everytime. So I just checked for integral part of the coefficient.

This comment has been minimized.

@parsoyaarihant

parsoyaarihant Jun 15, 2018

Contributor

Can you add this as a comment? Explaining why you are using int

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 5, 2018

like variable shape of the cross-section?

@parsoyaarihant

This comment has been minimized.

Contributor

parsoyaarihant commented Jun 5, 2018

Yes

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 5, 2018

yeah, it can be added. Maybe we can have precomputed second_moment of some of the basic shapes of cross-section and input the dimensions of that shape while initialising Beam object.

@parsoyaarihant

This comment has been minimized.

Contributor

parsoyaarihant commented Jun 5, 2018

I am referring to situations where I = x**2 where x is the length of the beam.

@moorepants

This comment has been minimized.

Member

moorepants commented Jun 5, 2018

I think we need some more careful thought on the API here. Currently we have a beam that we add and substract loadings to that constructs the proper sing funcs. I'm wondering if composite beams (different discrete changes in I and/or E) should be constructed by adding together multiple beams. Something like:

b1 = Beam(E1, I1, l1)
b2 = Beam(E2, I2, l2)
total_beam = b1 + b2

This would constrain Beam to be strictly continguous shape/material but varying loads.

Another way is to "apply" cross sections and moduli like we do for the loads in some way.

b = Beam()
b.apply_cross_section(I1, x1=3, x2=4)

Lastly we could think of a new Beam object entirely. Not sure what that would look like.

And one more note, is how to think about what if E or I vary given a function: E = f(x)?

@moorepants

This comment has been minimized.

Member

moorepants commented Jun 5, 2018

It is worth noting that the current Beam object was only designed with beams that can be solved by Sing Funcs in mind. This is a strict subset of 2D beams (I believe).

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 5, 2018

how about for discrete values of I we do it by joining two beams. Like

b1 = Beam(E1, I1, l1)
b2 = Beam(E2, I2, l2)
b1.join(b2, via)

where via can be fixed or hinge telling the way both beams are joined.

For situations like I = f(x), i think we can do it by just passing it like Beam(length, E, f(x)) if we change integrate(self.bending_moment(), x) to integrate(self.bending_moment()/f(x), x) , considering no problem comes in its integration.

@moorepants

This comment has been minimized.

Member

moorepants commented Jun 5, 2018

I like the join method idea. Would via be a new object representing the joint? Or just flag? How many joint types are needed?

For I, E = f(x) things should work as expected if they are passed into Beam.

@moorepants

This comment has been minimized.

Member

moorepants commented Jun 5, 2018

Also, does join join on the left or right? Do we have that concept?

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 5, 2018

I think using via like a flag should be fine. Till now I have seen beams either fixed axially (like above) or with a hinge (for example here).

b1.join(b2, fixed) should join the b2 at the right end of b1. This is just another way to represent a new beam with discrete values of I, solving stratergy should be same.

@parsoyaarihant

This comment has been minimized.

Contributor

parsoyaarihant commented Jun 6, 2018

We can have multiple types of supports:
screen shot 2018-06-06 at 11 09 19 am

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 6, 2018

for supports, we can have apply_support method(I think it is in our timeline). But for creating composite beams I added join method. Have a look, will add support for beams joined using hinge in a separate PR.

>>> R1, R2 = symbols('R1, R2')
>>> b1 = Beam(2, E, 1.5*I)
>>> b2 = Beam(2, E, I)
>>> b1.join(b2, "fixed")

This comment has been minimized.

@moorepants

moorepants Jun 6, 2018

Member

I'm not sure we should mutate b1. Would it be better to do:

b3 = b1.join(b2, 'fixed')

That way you can make use of b1 and b2 without worrying about them being mutated.

>>> b1.join(b2, "fixed")
>>> b1.apply_load(20, 4, -1)
>>> b1.apply_load(R1, 0, -1)
>>> b1.apply_load(R2, 0, -2)

This comment has been minimized.

@moorepants

moorepants Jun 6, 2018

Member

Will join work if you apply loads before joining?

This comment has been minimized.

@jashan498

jashan498 Jun 7, 2018

Contributor

yeah, it would but loads would not be transferred to the new beam.

@parsoyaarihant parsoyaarihant added the GSoC label Jun 9, 2018

@jashan498 jashan498 changed the title from Added support for beams with variable second moment to [WIP]Added support for composite beams Jun 11, 2018

@jashan498 jashan498 changed the title from [WIP]Added support for composite beams to Added support for composite beams Jun 15, 2018

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 15, 2018

@parsoyaarihant @moorepants I have added support for beams connected via hinge too. PR is ready to get reviewed now.
Algorithm used for solving hinged beams
Source for the test case

10*SingularityFunction(x, 4, 2))/(E*I), x <= 2), (((80*SingularityFunction(x, 0, 1) -
10*SingularityFunction(x, 0, 2) + 10*SingularityFunction(x, 4, 2))/I - 120/I)/E + 80.0/(E*I), x <= 4))
"""
if via == "fixed":

This comment has been minimized.

@parsoyaarihant

parsoyaarihant Jun 15, 2018

Contributor

This condition is same as the next condition for most part. Can you take out the common part out from the conditions?

@@ -390,6 +459,129 @@ def applied_loads(self):
"""
return self._applied_loads
def _solve_hinge_beams(self, *reactions):

This comment has been minimized.

l=symbols('l', positive=True)
R1, M1, R2, R3, P = symbols('R1 M1 R2 R3 P')
b1=Beam(2*l, E, I)

This comment has been minimized.

@parsoyaarihant

parsoyaarihant Jun 15, 2018

Contributor

Can you add whitespace before and after =

@parsoyaarihant

This comment has been minimized.

Contributor

parsoyaarihant commented Jun 18, 2018

@jashan498 do you plan to make further changes?

@jashan498

This comment has been minimized.

Contributor

jashan498 commented Jun 19, 2018

Nah, I made all the requested changes. Looking for further review

@parsoyaarihant parsoyaarihant merged commit 1599d49 into sympy:master Jun 19, 2018

1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details
>>> b.load
80*SingularityFunction(x, 0, -2) - 20*SingularityFunction(x, 0, -1) + 20*SingularityFunction(x, 4, -1)
>>> b.slope()
Piecewise((0.666666666666667*(80*SingularityFunction(x, 0, 1) - 10*SingularityFunction(x, 0, 2) +

This comment has been minimized.

@moorepants

moorepants Jul 28, 2018

Member

Can you explain why this requires a Piecewise() in the expression?

This comment has been minimized.

@jashan498

jashan498 Jul 29, 2018

Contributor

Because the expression for slope would depend on the location of point. Expression would change depending upon which sub-beam the point lies on (due to different E and I values).

This comment has been minimized.

@jashan498

jashan498 Jul 29, 2018

Contributor

We can use SingularityFunction in place of Piecewise here but then expression becaomes hard to read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment