**Example use-case of Column class:**

>>> from sympy.physics.continuum_mechanics.column import Column >>> from sympy import Symbol, symbols >>> E, I, P = symbols('E, I, P', positive=True) >>> c = Column(3, E, I, 78000, top="pinned", bottom="pinned") >>> c.end_conditions {'bottom': 'pinned', 'top': 'pinned'} >>> c.boundary_conditions {'deflection': [(0, 0), (3, 0)], 'slope': [(0, 0)]} >>> c.moment() 78000*y(x) >>> c.solve_slope_deflection() >>> c.deflection() C1*sin(20*sqrt(195)*x/(sqrt(E)*sqrt(I))) >>> c.slope() 20*sqrt(195)*C1*cos(20*sqrt(195)*x/(sqrt(E)*sqrt(I)))/(sqrt(E)*sqrt(I)) >>> c.critical_load() pi**2*E*I/9

The Column class is non-mutable, which means unlike the Beam class, a user cannot change the attributes of the class once they are defined along with the object definition. Therefore to change the attribute values one will have to define a new object.

- From a backward-compatibility perspective, it is always possible to adopt a different plan and add mutability later but not the other way around.
- Most things are immutable in SymPy which is useful for caching etc. Matrix is an example where allowing mutability has lead to many problems that are now impossible to fix without breaking backwards compatibility.

The **governing equation** for column buckling is:

If we determine the the **moment equation** of the column ,on which the buckling load is applied, and place it in the above equation, we might be able to get the deflection by further solving the differential equation for **y**.

**Step-1: To determine the internal moment.**

This is simply done by assuming deflection at any arbitrary cross section at a distance** x** from the bottom as **y **and then multiplying this by the load **P** and for eccentric load another moment of magnitude **P*e** is added to the moment.

**Simple load** **is given by**:

**Eccentric load is given by: **

**Step-2: **This moment can then be substituted in the governing equation and the resulting differential equation can be solved using SymPy’s **dsolve()** for the **deflection y**.

The above steps considers a simple example of a column pinned at both of its ends. But the end-condition of the column can vary, which will cause the moment equation to to vary.

Currently **four** basic supports are implemented: Pinned-pinned, fixed-fixed, fixed-pinned, one pinned-other free.

Depending on the supports the moment due to applied load would change as:

**Pinned-Pinned:**no change in moment

**Fixed-fixed**: reaction moment M is included

**Fixed-pinned:**

Here **M** is the restraint moment at **B (**which is fixed**). **To counter this, another moment is considered by applying a horizontal force **F** at point A.

**One pinned- other free:**

Once we get the deflection equation we can solve for the slope by differentiating the deflection equation with respect to **x**. This is done by SymPy’s **diff()** function

self._slope = self._deflection.diff(x)

Critical load for single bow buckling condition can be easily determined by the substituting the boundary conditions in the deflection equation and solving it for **P** i.e the load.

**Note:** Even if the user provides the applied load, during the entire calculation, we consider the load to be **P**. Whenever the **moment()**, **slope(), deflection(),** **etc**. methods are called the variable **P **is replaced with the users value. This is done so that it is easier for us to calculate the critical load in the end.

defl_eqs = [] # taking last two bounndary conditions which are actually # the initial boundary conditions. for point, value in self._boundary_conditions['deflection'][-2:]: defl_eqs.append(self._deflection.subs(x, point) - value) # C1, C2 already solved, solve for P self._critical_load = solve(defl_eqs, P, dict=True)[0][P]

The case of the pinned-pinned end condition is a bit tricky. On solving the differential equation via **dsolve()**, the deflection comes out to be zero. This problem has been described in this blog. Its calculation is handled a bit differently in the code. Instead of directly solving it via **dsolve()**, it is solved in steps, and the trivial solutions are removed. This technique not only solves for the deflection of the column, but simultaneously also calculates the critical load it can bear.

Although this may be considered as a hack to the problem. I think in future it would be better if **dsolve()** gets the ability to remove the trivial solutions. But this seems to be better as of now.

A problem that still persists is the calculation of critical load for pinned-fixed end condition. Currently, it has been made as an XFAIL, since to resolve that either **solve()** or **solveset() **has to return the solution in the required form. An issue has been raised on GitHub, regarding the same.

Hope that gives a crisp idea about the functioning of SymPy’s Column module.

Thanks!

]]>The week started with the merge of PR #17001 which implemented a method **cut_section()** in the polygon class, in order to get two new polygons when a polygon is cut via a line. After this a new method **first_moment_of_area()** was added in PR #17153. This method used **cut_section()** for its implementation. Tests for the same were added in this PR. Also the existing documentation was improved. I also renamed the **polar_modulus()** function to **polar_second_moment_of_area() **which was a more general term as compared to the previous name. This PR also got **merged** later on.

Now, we are left with two more PR’s to go. PR #17122 (Column Buckling) and PR #17345 (Beam diagram). The column buckling probably requires a little more documentation. I will surely look into it and add some more explanations and references to it. Also, the beam diagram PR has been completed and documented. A few more discussions to be done on its working and we will be ready with it.

I believe that by the end of this week both of these will finally get a merge.

Another task that remains is the implementation of the Truss class. Some rigorous debate and discussion is still needed to be done before we start its implementation. Once we agree on the implementation needs and API it won’t be a difficult task to write it through.

Also, since the final evaluations have started I will be writing the project report which I have to submit before the next week ends.

Since officially the coding period ends here, there would be no ToDo’s for the next week, just the final wrapping up and will surely try to complete the work that is still left.

Will keep you updated!

Thanks!

]]>As mentioned in the previous blog this PR was an attempt to make the **draw()** function use SymPy’s own plot() rather than importing matplotlib externally to plot the diagram. The idea was to plot the load equation which is in terms of singularity function. This would directly plot uniformly distributed load, uniformly varying load and other higher order loads except for point loads and moment loads.

The task was now to plot the remaining parts of the diagram which were:

- A rectangle for drawing the beam
- Arrows for point loads
- Markers for moment loads and supports
- Colour filling to fill colour in inside the higher order loads (order >=0).

Instead of making temporary hacks to implement these, I went a step further to give the plotting module some additional functionalities. Apart from helping in implementing the **draw()** function, this would also enhance the plotting module.

The basic idea was to have some additional keyworded arguments in the **plot()** function. Every keyworded argument would be a list of dictionaries where each dictionary would represent the arguments (or parameters) that would have been passed in the corresponding matplotlib functions.

These are the functions of matplotlib that can now be accessed using **sympy’s plot()**, along with where there are used in our current situation:

- matplotlib.patches.Rectangle -to draw the beam
- matplotlib.pyplot.annotate – to draw arrows of load
- matplotlib.markers– to draw supports and moment loads
- fill_between() – to fill an area with color

Another thing which is worth mentioning is that to use **fill_between() **we would require numpy’s **arange()** for sure. Although it might be better if we could avoid using an external module directly, but I guess this is unavoidable for now.

Also, I have added an option for the user to scale the plot and get a pictorial view of it in case where the plotting with the exact dimensions doesn’t produce a decent diagram. For eg. If the magnitude of the load (order >= 0) is relatively higher to other applied loads or to the length of the beam, the load plot might get out of the final plot window.

Here is an example:

>>> R1, R2 = symbols('R1, R2') >>> E, I = symbols('E, I') >>> b1 = Beam(50, 20, 30) >>> b1.apply_load(10, 2, -1) >>> b1.apply_load(R1, 10, -1) >>> b1.apply_load(R2, 30, -1) >>> b1.apply_load(90, 5, 0, 23) >>> b1.apply_load(10, 30, 1, 50) >>> b1.apply_support(50, "pin") >>> b1.apply_support(0, "fixed") >>> b1.apply_support(20, "roller") # case 1 on the left >>> p = b1.draw() >>> p.show() # case 2 on the right >>> p1 = b1.draw(pictorial=True) >>> p1.show()

- Getting leftover PR’s merged
- Initiating implementation of Truss class

Will keep you updated!

Thanks!

]]>For the last phase we have Truss calculations to be implemented in the continuum_mechanics module. I had initiated a discussion regarding what needs to be done and how the implementation will move forward in an issue #17302. We will have to analyse a bit more about making Truss calculations symbolic and what benefits one might get in solving it symbolically. We have some good packages to compare from like this. I guess a bit more discussion is needed before we go ahead with it.

Besides this, I had worked on improving the **draw()** function implemented in the previous week in PR #17240. I modified it to use the **_backend** attribute for plotting the beam diagram. This could have worked until I realised that using the **_backend** attribute doesn’t really has affect the **Plot object. **To understand the last statement, lets go to how **sympy.plot() **works.

In simple terms, the equations that we pass through the **plot()** function as arguments are actually stored in** _series** attribute. So we can indirectly say that the basic data of the plot is stored in this attribute. But using the **_backend **attribute wouldn’t alter **_series **at all and if **_series **remains empty at the start it would end up storing nothing.

But we are of course getting a decent plot at the end, so shouldn’t we probably ignore this? No, it would surely give the plot but we won’t be getting a fully defined** Plot **object which we can further use with **PlotGrid** to get a subplot which includes all the five plots related to the beam.

Keeping this in mind, I tried an alternative way to directly use** sympy.plot() ** to give the plot. Although a bit hard and time taking to do, I have intiated this in a draft PR #17345. This PR perfectly plots a rectangular beam and loads (except point and moment loads). Only things that are left here are to plot supports and arrows denoting the direction of the load.

The example below shows how it functions: (keep in mind it just plots the basic structure of the intended beam diagram, it hasn’t been completed yet)

>>> E, I = symbols('E, I') >>> b = Beam(9, E, I) >>> b.apply_load(-12, 9, -1) # gets skipped >>> b.apply_load(50, 5, -2) # gets skipped >>> b.apply_load(3, 6, 1, end=8) >>> b.apply_load(4, 0, 0, end=5) >>> b.draw()

I also tried to complete the leftover PR’s in this week, but still some work is left.

- Completing the
**draw()**function - Documentation and testing
- Starting Truss implementations

Will keep you updated!

Thanks!

]]>There has been some discussions in the PR #17240 which implements the **draw() **function. We might change the name of the function to **plot() **which is more consistent with the previous beam methods **plot_shear_force()**, **plot_bending_moment(), **etc.

Another discussion was about making this beam diagram a part of the **plot_loading_results(), **which basically intends to plot all the beam related plots. Although currently the beam diagram uses **matplotlib **as an external module, whereas the **plot_loading_results()** uses **PlotGrid** which is Sympy’s internal functionality. So it would be a bit tricky to merge those two.

We also discussed the idea or rather the possibility of directly making use of SymPy’s own plot to create a beam diagram. SymPy’s **plot() **is capable to plotting Singularity functions, so the load applied on the beam can also be plotted using **sympy.plot() **as beam.load is indeed in terms of singularity function. But there is a problem when it comes to point loads and moment loads as the are in terms singularity function of negative order (or exponent). Not sure whether the sympy plot for singularity functions of negative order is plotted correctly, but the current plot won’t help us in drawing point loads and moment loads. We might have to deal with it separately.

I have opened a discussion in the mailing list regarding whether the plot is correct for singularity functions of negative order, or what else should be done in order to get it corrected.

Also, it will be difficult to plot a rectangle (for making beam) and markers (for making supports) via sympy.plot(). One idea is to go with the **_backend** attribute of sympy.plot() which helps in directly using the **backend **(i.e. matplotlib backend). I will have a look over it.

Of
course if the beam diagram is made using SymPy’s own plot it would surely be
preferred but for that we also need work on **sympy.plot()** as currently it is limited to certain functionalities.

From the next week I will be starting with the last phase of implementing a Truss structure and its respective calculations.

Since only last few weeks are left, I think I will be able to make a draft PR for the last phase implementation by the end of the next week. And then we would only be left with minor things and leftovers of the previous phases.

Also, I am glad to share that I was able to pass the second evaluations. So once again thank you mentors for all your support and guidance!

- Starting phase-IV implementations
- Simultaneously working and discussing previous PR’s.

Will keep you updated!

Thanks!

]]>Last week was a bit of research-based, understanding **matplotlib **and how it can be used to plot a beam diagram. I had a conversation with Jason Moore and Jashan where Jason shared a link of a repository, which also was a bit of help as I took some hints from it for the **draw() **function. After a lot of investigation and analysis, I was finally able to make a draft PR # 17240 which did the work as we intended.

Here is an example of how it would function:

# This example has no prior logic involved. It just tests whether every functionality works or not >>> E, I = symbols('E, I') >>> b1 = Beam(50, E, I) >>> b1.apply_load(-10, 0, -1) >>> b1.apply_load(R1, 10, -1) >>> b1.apply_load(R2, 30, -1) >>> b1.apply_load(9, 5, 0, 23) >>> b1.apply_load(9, 30, 1, 50) >>> b1.apply_support(50, "pin") >>> b1.apply_support(0, "fixed") >>> b1.apply_support(20, "roller") >>> b1.draw()

Here we are using **matplotlib** and **numpy** by importing them as external modules. Of course, it would be better to have it done via **SymPy’s** own **plot()**, but I think that is something we could work on in later stages as** SymPy’s plot()** is limited to work on equations and stuff (although on can use **_backend **attribute for further functionalities). Also to be noted here that **SymPy’s plot()** is not a replica of **matplotib’s plot()** but it makes it easier for SymPy equation to be plotted and it uses **matplotlib** to do so.

Following are the** m****atplotlib** modules/classes used:

- matplotlib.patches.Rectangle -to draw the beam
- matplotlib.pyplot.annotate – to draw arrows of load
- matplotlib.markers– to draw supports

Also, considering Jason’s comment in the PR, I will have to work on making **SymPy’s plot()** to accept a singularity function, so that it would be easier to plot **loads **which are indeed equations of Singularity function. This is still in consideration, so I will have to look into it and of course will have a discussion on how it is to be done.

Currently, I am not able to determine how to plot parabolic loads. I think this could be added later as we should currently focus on plotting simple parts and certainly work on other complexities later. But we can have a discussion on it.

Other PR’s are still being parallelly worked on.

- Working on the idea of plotting singularity function via SymPy’s plot()
- Plotting parabolic loads
- Writing documentation and tests

Will keep you updated!

Thanks!

]]>The documentation and tests have been written and with some changes in the **solve_slope_deflection()** and **critical_load(),** the **Column** class is now able to handle cases with trivial solutions of the constants ( C1 & C2) which made the deflection equation zero.

Apart from this, another problem that we had with the **pinned-fixed** end condition, where **solve()** wasn’t giving the output in the required form, has temporary been handled by making an **XFAIL **test against it. We can work on it later. Either there has to be some changes in **solve()** so that we would be able to handle our case or we might have to figure out a way to rewrite it into the desired form.

With the end of this week, PR #17122 and PR #17153 are complete and ready for review. I have made some changes addressing some of the reviews, and we can have further discussions on it.

Now, also moving on to the next phase, I have done a bit of research on it. I will most probably open a discussion to have an initial discussion regarding how work will progress in this stage. This phase is regarding plotting the beam diagrams using matplotlib. I have also considered **pyglet** plotting module of SymPy, which according to the documentation is capable of plotting geometries, but there has been some problems in this module and it doesn’t seem to be working well. I had earlier made an issue #16537 regarding the same, but there seems to be no improvement here.

So, we will be discussing the rest in an issue-cum-discussion, in the upcoming week.

**Next week:**

- Working on the Stage-III
- Simultaneously, discussing the leftover PR’s and trying to finish them and make a merge.

Most probably, on successful discussion and planning, I will be opening a draft work-in-progress PR for the **draw()** function in stage –III.

Will keep you updated!

Thanks!

]]>Last week the work was majorly focused on the work in progress PR #17122. I have included the critical load function which makes the Column class capable of determining the critical load. Some problems still came up in solving some equations. I have made an issue related to those.

An equation similar to **tan(x) – x** comes up while determining the critical load for the **pinned-fixed** end-condition. SymPy’s **solve() **won’t be able to solve such an equation, and as per the solution given in the issue, I think that **nsolve()** would surely help in this case. So I will be going ahead to solve it using the approximation returned by **nsolve()** to handle this condition.

Another problem that I faced was determining deflection and critical load for the **pinned-pinned** end-condition. Here, the deflection comes out to be:

**C1*sin(sqrt(P)*x/(sqrt(E)*sqrt(I)))** +** C2*cos(sqrt(P)*x/(sqrt(E)*sqrt(I)))**

Now on solving it for constants **C1** and **C2, **using initial boundary conditions, both come out to be **0**, making the deflection **zero**. This implies that no buckling occurs, which is not the case.

Even when solving it manually, this situation occurs, we deal with it by putting **C2 = 0 **and instead of putting **C1 = 0,** we consider the **sin **term equal to zero and then solve for **P (critical load). **So, I will be adding a few more lines of code to deal with this situation.

Apart from working on this module, I have also opened another PR #17153 which implement methods to determine **section modulus** and **polar modulus** of any polygon (more precisely a cross-section). Initially it was a draft PR, but now the work has been completed on it. Once I get the approval, I will also be adding the same for the Ellipses module. Also, if **cut_section() **gets successfully implemented I will be adding another method to determine the first moment.

I am pretty sure the work on **Column class** will be successfully completed before the end of the next week. Also, we will be heading towards the next stage which intends to plot beam diagrams using matplotlib. Till then we can have an initial discussion regarding the same.

- Improving the
**critical_load()**to handle the above problems - Completing the Column class (documentation and tests)
- Starting with the next phase

Will keep you updated!

Thanks!

]]>Although we need to add some examples in the docs, to make it easier for the user to understand how to use this new feature.

Coming on to stage-II, I had already, initiated a discussion to finalize the API of the new Column class that is to be implemented as a part of the continuum mechanics module in this stage.

We concluded that it would be much better if the Column class remains non-mutable i.e. unlike the beam class where a beam is formed in a piecewise form, the new Column class would take all its required input data during the declaration and then one can call different methods to calculate different things.

I have made a work-in-progress PR #17122 implementing the Column class which performs the required buckling calculations. Currently, I have not included a method to calculate the critical load as there was a bit of problem with the form of the equation which the **dsolve() **returns after solving the differential equation of buckling. **dsolve(**) is SymPy’s differential equation solver.

In general, if we solve the general equation of buckling manually, we might apply the **method of undetermined coefficients**, which of course even **dsolve() ** is capable to apply, but it gives the answer in an exponent form, while we need it in a trigonometric form (for ease of further calculations). So after seeking different methods trying to convert this equation in terms of **sin(x)** and **cos(x), **I finally had to put that problem in the discussion, where Oscar Benjamin, gave an idea to declare the variables as positive in order to get it in terms of **sin **and** cos. **I tried that it works well for our case. I will have to figure out the further calculation of the critical load.

Hopefully will be updating the code with a new method to calculate critical load, soon.

Also, I have planned to have a method to solve the **unknown reactions** and **reaction moments**, which would use the **boundary conditions** to get their values.

With all these things going on, this week we also had our first evaluations, and I am very happy to say that I have passed it. **Thanks to the mentors!**

- Completing Column class with all its methods
- Adding tests and documentation.
- Starting discussions for the next stage.

I will try to finish working on the Column class this weekend.

Will keep you updated!

Thanks!

]]>There is no special function for defining the cross-section of a Beam object. A user can simply pass the geometry object as a parameter instead of the **second_moment, **and the corresponding second moment would be calculated internally. The example below might explain this better:

>>> b = Beam(l, E, Circle((0, 0), r)) >>> b.second_moment pi*r*Abs(r)**3/4 >>> b.cross_section Circle(Point2D(0, 0), r)

Further, the **cross_section** attribute can be changed even after the beam is created. Every time the **cross_section** is assigned a new value, the **second_moment** gets automatically updated.

Similarly, every time the user changes the **second_moment** explicitly after the creation of the beam, the previous **cross_section** gets destroyed, or in other words, the **cross_section** is set to None.

>>> b = Beam(l, E, Circle((0, 0), r)) >>> I = Symbol(‘I’) >>> b.second_moment = I >>> b.cross_section None >>> b.second_moment = Polygon((0, 0), (a, 0), (a, b), (0, b)) ValueError: To update cross-section geometry use `cross_section` attribute

The PR is complete and just needs the final approval from the mentors.

Simultaneously, I had worked on the column buckling calculations which is a part of the stage –II.

I have opened an issue-cum-discussion for discussing its API and further implementations.

Since the calculations of the Column Buckling are very much different from those of beam bending, we will have to make a separate class Column. The basic API and the way the calculations are supposed to go can be seen from the stage –II in the proposal.

I would be making a PR for column buckling calculations within a day or two, once some initial questions (as mentioned in the issue-cum-discussion) gets clarified.

- Finalizing the basic API and implementations of Column class
- Making a PR for the above implementations
- Documentation and testing

Will keep you updated!

Thanks!

]]>