# sympy/sympy

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
+294 −2

## Conversation

Projects
None yet
4 participants
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.

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

``` added support for variable second moment ```
``` 7d781ee ```

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.
``` changed moment type to Piecewise ```
``` 7e388b0 ```

### moorepants reviewed Jun 5, 2018

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

#### 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.

#### jashan498 Jun 5, 2018 • edited

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`)

Contributor

### parsoyaarihant commented Jun 5, 2018

 Should we add support for variable `I` along the length?

### jashan498 reviewed Jun 5, 2018

 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)

#### 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.

#### parsoyaarihant Jun 15, 2018

Contributor

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

Contributor

### jashan498 commented Jun 5, 2018

 like variable shape of the cross-section?
Contributor

 Yes
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.
Contributor

### parsoyaarihant commented Jun 5, 2018

 I am referring to situations where `I = x**2` where x is the length of the beam.
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)?
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).
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.
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.
Member

### moorepants commented Jun 5, 2018

 Also, does `join` join on the left or right? Do we have that concept?
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.
``` second_moment representation changed to SingularityFunction ```
``` 135a9e2 ```

Contributor

### parsoyaarihant commented Jun 6, 2018

 We can have multiple types of supports:
Contributor

### jashan498 commented Jun 6, 2018 • edited

 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.
``` added join method for composite beams ```
``` 2040f0b ```

### moorepants reviewed Jun 6, 2018

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

#### 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.

### moorepants reviewed Jun 6, 2018

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

#### moorepants Jun 6, 2018

Member

Will join work if you apply loads before joining?

#### jashan498 Jun 7, 2018

Contributor

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

### jashan498 added some commits Jun 7, 2018

``` join now returns a Beam instance ```
``` c1c3700 ```
``` updated docstring ```
``` 58c4300 ```

### parsoyaarihant added the GSoC label Jun 9, 2018

``` started adding support for beams connected via hinge ```
``` 9864cf9 ```

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

``` added main solver method for hinged beams ```
``` 948f39a ```

### jashan498 added some commits Jun 13, 2018

``` _solve_hinge_beam can find support reactions ```
``` b42d454 ```
``` added test case for hinged beam ```
``` b865542 ```
``` added docstring ```
``` acc99c0 ```
``` Some minor changes ```
``` b427033 ```

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

### parsoyaarihant reviewed Jun 15, 2018

 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":

#### parsoyaarihant Jun 15, 2018 • edited

Contributor

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

### parsoyaarihant reviewed Jun 15, 2018

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

Contributor

### parsoyaarihant reviewed Jun 15, 2018

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

#### parsoyaarihant Jun 15, 2018

Contributor

Can you add whitespace before and after `=`

``` Some minor changes in the docstring ```
``` 54ec990 ```
Contributor

### parsoyaarihant commented Jun 18, 2018

 @jashan498 do you plan to make further changes?
Contributor

### jashan498 commented Jun 19, 2018 • edited

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

### parsoyaarihant merged commit `1599d49` into sympy:master Jun 19, 2018 1 check passed

#### 1 check passed

continuous-integration/travis-ci/pr The Travis CI build passed
Details

### moorepants reviewed Jul 28, 2018

 >>> 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) +

#### moorepants Jul 28, 2018

Member

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

#### 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).

#### jashan498 Jul 29, 2018

Contributor

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

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