JWock82 / PyNite

A 3D structural engineering finite element library for Python.
MIT License
421 stars 86 forks source link

CylidnerMesh origin wrong when not using axis='Y' #164

Closed SoundsSerious closed 11 months ago

SoundsSerious commented 12 months ago

Hello,

Thanks for making such an awesome library!

I am using cylinder meshes in the Z direction, however the starting value begins at 0 which corresponds to the y value input at the origin.

From Mesh.py line 1276

        radius = self.radius
        h = self.h
        y = self.origin[1]   #<< this is the problem there should be a look up per
        n = int(self.start_node[1:])
        q = int(self.start_element[1:])

        element_type = self.element_type

        # Determine the number of quads to mesh the circumference into
        if num_elements == None:
            num_elements = int(2*pi/mesh_size)

        # Mesh the cylinder from the bottom toward the top
        while round(y, 10) < round(h, 10):

            height = h - y                  # Remaining height to be meshed
            n_vert = int(height/mesh_size)  # Number of times the plate height fits in the remaining unmeshed height
            h_y = height/n_vert             # Element height in the vertical direction

            # Create a mesh of nodes for the ring
            if self.axis == 'Y':
                ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, y, 0],
                                        self.axis, 'N' + str(n), 'Q' + str(q), element_type)
            elif self.axis == 'X':
                ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [y, 0, 0],
                                        self.axis, 'N' + str(n), 'Q' + str(q), element_type)
            elif self.axis == 'Z':
                ring = CylinderRingMesh(radius, h_y, num_elements, thickness, material, self.model, 1, 1, [0, 0, y],
                                        self.axis, 'N' + str(n), 'Q' + str(q), element_type)

I think this would be an easy fix:


        radius = self.radius
        h = self.h
        if self.axis == 'Y':
            y = self.origin[1]  
        elif self.axis == 'X':
            y = self.origin[0]  
        elif self.axis == 'Z':
             y = self.origin[2]  
        n = int(self.start_node[1:])
        q = int(self.start_element[1:])
SoundsSerious commented 12 months ago

Also i think it might be a good idea to feed in the other origin coordinates to the CylinderRingMesh

JWock82 commented 11 months ago

Thanks for bringing this to my attention. I've made the fix to the repository. The fix will be included with the next release of Pynite.

The CylinderRingMesh does not have the same issue as far as I can tell, since it only deals with a single course of plates about its origin. The CylinderMesh dealt with multiple courses, which required use of the variable y that changed with each successive course.

SoundsSerious commented 11 months ago

@JWock82 Awesome! This library is helping me so much especially using https://sectionproperties.readthedocs.io/en/latest/ to get accurate 2D fea and moments of inertia.

I really like the load cases and combos, thats helping me alot doing some wind turbine analysis with complex loading. Pasted image 20230715121231

2D FEA helps alot too with complex deformation and optimizing for low weight Pasted image 20230715121143

I have a somewhat ready integration between these two libs here, but its not really documented well yet (on my very long todo list :) https://github.com/Ottermatics/ottermaticslib https://ottermatics.github.io/ottermaticslib/build/html/ottermatics.html#module-ottermatics.structure

I was thinking it would be a cool idea to use the shapley.exterior polygon to render the beam exterior through VTK in pynite but I'm still pondering an integration or how to extend the PyNite.render_model .

Would some kind of integration between any three of these libraries be interesting to you? We could save alot of time by building a common material class for example

JWock82 commented 11 months ago

What you're doing here is really cool! I'm very impressed!

I'm all for integrating libraries, as far as software license rule issues don't get in the way. Pynite is very liberal (MIT license), but my understanding is that GPL libraries are "viral" and may not be able to be integrated fully with Pynite without changing Pynite's license to GPL too.

The biggest hold up for me is that I just don't have a lot of free time myself. I like you have a very long "to do" list. Right now I'm focused on simplification and modularization of the analysis code. This will make it easier to implement new types of analysis in the future (dynamics, pushover, etc.).

Then there's units, steel design, concrete design, shear wall analysis, triangular plate elements, delauney triangulation for meshes, von-mises stress results... the list just keeps on going.

One of these days maybe this project will attract some funding to boost development. Until then, it's a volunteer effort that moves a little slower.

SoundsSerious commented 11 months ago

@JWock82 Thanks! I feel we're both probably aiming at the same problem... making the hard engineering problems easier!

I am completely on the same page about lack of time and resources, theres a million things to do that should be done, but I can only do one at a time. Perhaps this is the case for some kind of joint open-source engineering foundation. To attract some resources as you point out to make it self-sustaining, and that should be totally reasonable your project makes free what some charge for quite a bit.

The timescale for my project is years as I'll be doing this stuff the rest of my life so I guess I'm not in a rush to the finish line! To your point about licenses I think both ottermaticslib and sectionproperties are MIT so that is at least one less problem to consider. I am currently thinking about rebranding my project to seem less proprietary and more open-source.

For your refactor you may want to consider some meta-programming techniques that are in ottermaticslib since that allows some reliable class customization. The attrs framework overrides the init method so you have a reliable Input interface you can derive knowledge from about types ect. This allows the tabulation of input separately from output with the custom_decorators strategy. You mark functions by purpose and can validate their IO and do stuff like caching or plotting. This is all kind of experimental but focusing on class modification before creating an instance helps to solve composition problems that would have otherwise been handled in __init__.

That strategy has helped me a ton since I am usually writing custom analysis for complex systems with lots of variables, when it all shakes out you get a dataframe with the hierarchy of variables with minimal effort. In the structures module of ottermaticslib I'm working towards organizing this dataframe by load combo and beam x-position in the Structure class but thats a WIP. Thinking there might be some interesting benefits to creating a networkx graph to identify contiguous beams and then plot forces / moments / stress on them to reduce the apparent dimensionality.

I could probably talk about this stuff all day so if you ever want to reach out feel free to connect at ottermatics@altmails.com