The Column class implemented in PR #17122 enables the continuum mechanics module of SymPy to deal with column buckling related calculations. The Column module can calculate the moment equation, deflection equation, slope equation and the critical load for a column defined by a user.

**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**

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.

**Reasons for creating a non-mutable class**

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

**Working of the column class:**

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

**Applying different end-conditions**

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

## **Solving for slope and critical load**

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**

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!

## Leave a Reply