Profiling the code

Using PatchMesher to model a quarter of the plate

# sphinx_gallery_thumbnail_path = '_static/profiler.png'

SPARSE = False

import math
import sys
import numpy as np

from femedu.examples import Example

from femedu.domain import System, Node
from femedu.solver import NewtonRaphsonSolver, SparseSolver
from femedu.elements.linear import Triangle
from femedu.materials import PlaneStress
from femedu.mesher import *


class ExamplePlate10(Example):

    def problem(self):
        # ========== setting mesh parameters ==============

        Nx = 60        # number of elements in the mesh
        Ny = 40        # number of elements in the mesh

        Lx = 120.0    # length of plate in the x-direction
        Ly =  80.0    # length of plate in the y-direction
        R  = Ly / 2.

        # ========== setting material parameters ==============

        params = dict(
            E  = 200.,      # Young's modulus
            nu = 0.450,     # Poisson's ratio
            t  = 1.00       # thickness of the plate
        )

        # ========== setting load parameters ==============

        px  = 20.0         # uniform load normal to x=const
        py  =  0.0         # uniform load normal to y=const
        pxy =  0.0         # uniform shear load on x=const and y=const

        # ========== setting analysis parameters ==============

        target_load_level = 1.00     # reference load
        max_steps = 2                # number of load steps: 2 -> [0.0, 1.0]

        # define a list of target load levels
        load_levels = np.linspace(0, target_load_level, max_steps)

        #
        # ==== Build the system model ====
        #

        model = System()
        if SPARSE:
            model.setSolver(SparseSolver())
        else:
            model.setSolver(NewtonRaphsonSolver())

        # create nodes

        #  3---------2
        #  |         |
        #  |         |
        #  |         |
        #  1---------1

        pts = (
            ( 0, 0),
            (Lx, 0),
            (Lx, Ly),
            (0, Ly),
        )

        mesher = PatchMesher(model, pts[0], pts[1], pts[2], pts[3])
        nodes, elements = mesher.triangleMesh(Nx, Ny, Triangle, PlaneStress(params))

        # define support(s)

        ## find nodes at y==0 and x==0

        for node in nodes:
            X = node.getPos()
            if math.isclose(X[0], 0.0):
                node.fixDOF('ux')    # horizontal support left side
            if math.isclose(X[1], 0.0):
                node.fixDOF('uy')    # vertical support at y==0

        # ==== build the reference load ====

        # nodal loads
        dir = np.array([1.,0.])    # normal to surface
        x0  = np.array([Lx,0.0])   # reference point on the surface
        for node in nodes:
            X = node.getPos()
            if math.isclose(X[0],Lx):
                print(node.getID(), node.getPos())
                for elem in node.elements:
                    print('+', elem.getID(), end=' ')
                    for face in elem.faces:
                        dist = np.allclose( [ (x - x0) @ dir for x in face.pos ], 0.0 ) \
                            and np.allclose( [ t @ dir for t in face.tangent ], 0.0, atol=0.05)
                        if dist:
                            print(face.id, ":", face.area, end=' ')
                            face_idx = int(face.id[-1])
                            elem.setSurfaceLoad(face_idx, px, pxy)
                    print()

        #model.plot(factor=0, title="undeformed system", filename="plate06_undeformed.png", show_bc=1, show_loads=1)

        model.setLoadFactor(1.0)
        model.solve()

        #model.plot(factor=1., filename="plate06_deformed.png")

        #model.solver.showKt(filename="plate06_spy_Kt.png")
        #np.save("plate6_Kt.npy",model.solver.Kt)

Run the example by creating an instance of the problem and executing it by calling Example.run()

This time, we are running the example in the profiler, writing profiling data to file.

    import cProfile

    ex = ExamplePlate10()

    if SPARSE:
        cProfile.run('ex.run()','profile_data_sparse.txt')
    else:
        cProfile.run('ex.run()','profile_data_full.txt')
Node_1478 [120.   0.]
+ Elem_1936
+ Elem_1937 1937.2 : [[2. 0.]]
Node_1539 [120.   2.]
+ Elem_1937 1937.2 : [[2. 0.]]
+ Elem_2056
+ Elem_2057 2057.2 : [[2.00000000e+00 1.42108547e-14]]
Node_1600 [120.   4.]
+ Elem_2057 2057.2 : [[2.00000000e+00 1.42108547e-14]]
+ Elem_2176
+ Elem_2177 2177.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_1661 [120.   6.]
+ Elem_2177 2177.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_2296
+ Elem_2297 2297.2 : [[2. 0.]]
Node_1722 [120.   8.]
+ Elem_2297 2297.2 : [[2. 0.]]
+ Elem_2416
+ Elem_2417 2417.2 : [[2. 0.]]
Node_1783 [120.  10.]
+ Elem_2417 2417.2 : [[2. 0.]]
+ Elem_2536
+ Elem_2537 2537.2 : [[2. 0.]]
Node_1844 [120.  12.]
+ Elem_2537 2537.2 : [[2. 0.]]
+ Elem_2656
+ Elem_2657 2657.2 : [[2. 0.]]
Node_1905 [120.  14.]
+ Elem_2657 2657.2 : [[2. 0.]]
+ Elem_2776
+ Elem_2777 2777.2 : [[2. 0.]]
Node_1966 [120.  16.]
+ Elem_2777 2777.2 : [[2. 0.]]
+ Elem_2896
+ Elem_2897 2897.2 : [[2. 0.]]
Node_2027 [120.  18.]
+ Elem_2897 2897.2 : [[2. 0.]]
+ Elem_3016
+ Elem_3017 3017.2 : [[2. 0.]]
Node_2088 [120.  20.]
+ Elem_3017 3017.2 : [[2. 0.]]
+ Elem_3136
+ Elem_3137 3137.2 : [[2. 0.]]
Node_2149 [120.  22.]
+ Elem_3137 3137.2 : [[2. 0.]]
+ Elem_3256
+ Elem_3257 3257.2 : [[2. 0.]]
Node_2210 [120.  24.]
+ Elem_3257 3257.2 : [[2. 0.]]
+ Elem_3376
+ Elem_3377 3377.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2271 [120.  26.]
+ Elem_3377 3377.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_3496
+ Elem_3497 3497.2 : [[2.00000000e+00 2.84217094e-14]]
Node_2332 [120.  28.]
+ Elem_3497 3497.2 : [[2.00000000e+00 2.84217094e-14]]
+ Elem_3616
+ Elem_3617 3617.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2393 [120.  30.]
+ Elem_3617 3617.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_3736
+ Elem_3737 3737.2 : [[2.00000000e+00 1.42108547e-14]]
Node_2454 [120.  32.]
+ Elem_3737 3737.2 : [[2.00000000e+00 1.42108547e-14]]
+ Elem_3856
+ Elem_3857 3857.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2515 [120.  34.]
+ Elem_3857 3857.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_3976
+ Elem_3977 3977.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2576 [120.  36.]
+ Elem_3977 3977.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_4096
+ Elem_4097 4097.2 : [[2.00000000e+00 2.84217094e-14]]
Node_2637 [120.  38.]
+ Elem_4097 4097.2 : [[2.00000000e+00 2.84217094e-14]]
+ Elem_4216
+ Elem_4217 4217.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2698 [120.  40.]
+ Elem_4217 4217.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_4336
+ Elem_4337 4337.2 : [[2.00000000e+00 1.42108547e-14]]
Node_2759 [120.  42.]
+ Elem_4337 4337.2 : [[2.00000000e+00 1.42108547e-14]]
+ Elem_4456
+ Elem_4457 4457.2 : [[ 2.00000000e+00 -1.42108547e-14]]
Node_2820 [120.  44.]
+ Elem_4457 4457.2 : [[ 2.00000000e+00 -1.42108547e-14]]
+ Elem_4576
+ Elem_4577 4577.2 : [[2. 0.]]
Node_2881 [120.  46.]
+ Elem_4577 4577.2 : [[2. 0.]]
+ Elem_4696
+ Elem_4697 4697.2 : [[2. 0.]]
Node_2942 [120.  48.]
+ Elem_4697 4697.2 : [[2. 0.]]
+ Elem_4816
+ Elem_4817 4817.2 : [[2. 0.]]
Node_3003 [120.  50.]
+ Elem_4817 4817.2 : [[2. 0.]]
+ Elem_4936
+ Elem_4937 4937.2 : [[2. 0.]]
Node_3064 [120.  52.]
+ Elem_4937 4937.2 : [[2. 0.]]
+ Elem_5056
+ Elem_5057 5057.2 : [[2. 0.]]
Node_3125 [120.  54.]
+ Elem_5057 5057.2 : [[2. 0.]]
+ Elem_5176
+ Elem_5177 5177.2 : [[2. 0.]]
Node_3186 [120.  56.]
+ Elem_5177 5177.2 : [[2. 0.]]
+ Elem_5296
+ Elem_5297 5297.2 : [[2. 0.]]
Node_3247 [120.  58.]
+ Elem_5297 5297.2 : [[2. 0.]]
+ Elem_5416
+ Elem_5417 5417.2 : [[2. 0.]]
Node_3308 [120.  60.]
+ Elem_5417 5417.2 : [[2. 0.]]
+ Elem_5536
+ Elem_5537 5537.2 : [[2. 0.]]
Node_3369 [120.  62.]
+ Elem_5537 5537.2 : [[2. 0.]]
+ Elem_5656
+ Elem_5657 5657.2 : [[2. 0.]]
Node_3430 [120.  64.]
+ Elem_5657 5657.2 : [[2. 0.]]
+ Elem_5776
+ Elem_5777 5777.2 : [[2.00000000e+00 2.84217094e-14]]
Node_3491 [120.  66.]
+ Elem_5777 5777.2 : [[2.00000000e+00 2.84217094e-14]]
+ Elem_5896
+ Elem_5897 5897.2 : [[ 2.00000000e+00 -2.84217094e-14]]
Node_3552 [120.  68.]
+ Elem_5897 5897.2 : [[ 2.00000000e+00 -2.84217094e-14]]
+ Elem_6016
+ Elem_6017 6017.2 : [[2. 0.]]
Node_3613 [120.  70.]
+ Elem_6017 6017.2 : [[2. 0.]]
+ Elem_6136
+ Elem_6137 6137.2 : [[2. 0.]]
Node_3674 [120.  72.]
+ Elem_6137 6137.2 : [[2. 0.]]
+ Elem_6256
+ Elem_6257 6257.2 : [[2. 0.]]
Node_3735 [120.  74.]
+ Elem_6257 6257.2 : [[2. 0.]]
+ Elem_6376
+ Elem_6377 6377.2 : [[2. 0.]]
Node_3796 [120.  76.]
+ Elem_6377 6377.2 : [[2. 0.]]
+ Elem_6496
+ Elem_6497 6497.2 : [[2. 0.]]
Node_3857 [120.  78.]
+ Elem_6497 6497.2 : [[2. 0.]]
+ Elem_6616
+ Elem_6617 6617.2 : [[2. 0.]]
Node_3918 [120.  80.]
+ Elem_6617 6617.2 : [[2. 0.]]
+

Now it’s time to process the profiling data

    import pstats
    from pstats import SortKey

    if SPARSE:
        p = pstats.Stats('profile_data_sparse.txt')
        p.strip_dirs() #.sort_stats(-1).print_stats()
        p.sort_stats(SortKey.NAME)
        #p.print_stats()

        p.sort_stats(SortKey.CUMULATIVE).print_stats(20)
        p.sort_stats(SortKey.TIME).print_stats(20)

    else:
        p = pstats.Stats('profile_data_full.txt')
        p.strip_dirs() #.sort_stats(-1).print_stats()
        p.sort_stats(SortKey.NAME)
        #p.print_stats()

        p.sort_stats(SortKey.CUMULATIVE).print_stats(20)
        p.sort_stats(SortKey.TIME).print_stats(20)
Fri Apr 26 00:03:38 2024    profile_data_full.txt

         6567554 function calls (6303232 primitive calls) in 12.640 seconds

   Ordered by: cumulative time
   List reduced from 267 to 20 due to restriction <20>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000   12.655   12.655 {built-in method builtins.exec}
        1    0.000    0.000   12.655   12.655 <string>:1(<module>)
        1    0.000    0.000   12.655   12.655 Example.py:20(run)
        1    0.006    0.006   12.655   12.655 plot_plate10.py:46(problem)
        1    0.000    0.000   10.430   10.430 System.py:313(solve)
        1    0.000    0.000   10.430   10.430 NewtonRaphsonSolver.py:13(solve)
        4    0.000    0.000    9.177    2.294 NewtonRaphsonSolver.py:105(assemble)
        4    1.922    0.481    9.177    2.294 Solver.py:166(assemble)
    19200    0.081    0.000    5.349    0.000 Element.py:269(getForce)
    19200    1.977    0.000    5.268    0.000 Triangle.py:80(updateState)
        2    0.000    0.000    4.591    2.295 Solver.py:388(checkResiduum)
    38400    0.469    0.000    2.470    0.000 Triangle.py:155(computeSurfaceLoads)
        1    0.028    0.028    2.148    2.148 PatchMesher.py:99(triangleMesh)
   115200    0.645    0.000    1.392    0.000 Face2D.py:54(computeNodalForces)
        1    0.003    0.003    1.237    1.237 NewtonRaphsonSolver.py:58(solveSingleStep)
        1    1.220    1.220    1.220    1.220 linalg.py:329(solve)
    19200    0.030    0.000    1.175    0.000 Element.py:278(getLoad)
     4800    0.133    0.000    1.135    0.000 Triangle.py:10(__init__)
254400/4800    0.426    0.000    0.888    0.000 copy.py:128(deepcopy)
     4800    0.026    0.000    0.836    0.000 copy.py:259(_reconstruct)


Fri Apr 26 00:03:38 2024    profile_data_full.txt

         6567554 function calls (6303232 primitive calls) in 12.640 seconds

   Ordered by: internal time
   List reduced from 267 to 20 due to restriction <20>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    19200    1.977    0.000    5.268    0.000 Triangle.py:80(updateState)
        4    1.922    0.481    9.177    2.294 Solver.py:166(assemble)
        1    1.220    1.220    1.220    1.220 linalg.py:329(solve)
   153600    0.699    0.000    0.828    0.000 numeric.py:841(outer)
   115200    0.645    0.000    1.392    0.000 Face2D.py:54(computeNodalForces)
   639439    0.644    0.000    0.644    0.000 {built-in method numpy.array}
   230400    0.499    0.000    0.696    0.000 Node.py:467(getIdx4Element)
    38400    0.469    0.000    2.470    0.000 Triangle.py:155(computeSurfaceLoads)
    19201    0.427    0.000    0.543    0.000 PlaneStress.py:25(updateState)
254400/4800    0.426    0.000    0.888    0.000 copy.py:128(deepcopy)
   115201    0.335    0.000    0.425    0.000 numeric.py:67(zeros_like)
    76800    0.299    0.000    0.645    0.000 Node.py:416(getDeformedPos)
    77208    0.230    0.000    0.332    0.000 Node.py:313(getDisp)
    38400    0.155    0.000    0.601    0.000 Triangle.py:163(<listcomp>)
    24000    0.140    0.000    0.263    0.000 shape_base.py:219(vstack)
    14400    0.138    0.000    0.279    0.000 Face2D.py:16(initialize)
19200/4800    0.136    0.000    0.752    0.000 copy.py:227(_deepcopy_dict)
     4800    0.133    0.000    1.135    0.000 Triangle.py:10(__init__)
    14400    0.121    0.000    0.405    0.000 Faces.py:10(__init__)
    14400    0.098    0.000    0.503    0.000 Face2D.py:13(__init__)

Total running time of the script: (0 minutes 12.710 seconds)

Gallery generated by Sphinx-Gallery