A two–body impact problem

This is a simplest application of the HYBRID_SOLVER. The input files for this example are located in the solfec-1.0/examples/hybrid–solver0 directory. These are:

../../../_images/hs0.png

Fig. 50 Example hybrid-solver0: a two body impact problem

Fig. 50 states the problem. Both, the upper “Solfec-1.0” body and the lower “Parmec” body are modeled as rigid. The upper body falls under gravity and hits the lower body, initiating vibrations. There is no impact restitution between the two bodies, hence the two bodies stay and vibrate together, following the initial impact. We use this simple example to illustrate the methodology of creating a hybrid model.

Listing 1 includes the Parmec file hs0–parmec.py. The material is created in line 1 and the meshed lower cube is created in line 16. The cube’s motion is restrained along x, y translations and x, y, z rotations in line 18. The elastic spring is created in line 20. We note, that no damping is applied and that the spring direction is fixed along z. Gravity is applied in line 23. This concludes the input file.

Listing 1 Listing of hs0–parmec.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
matnum = MATERIAL (1, 1, 0.25)

nodes = [0, 0, 0,
         1, 0, 0,
	 1, 1, 0,
	 0, 1, 0,
	 0, 0, 1,
	 1, 0, 1,
	 1, 1, 1,
	 0, 1, 1]

elements = [8, 0, 1, 2, 3, 4, 5, 6, 7, matnum]

color = 1

parnum = MESH (nodes, elements, matnum, color)

RESTRAIN (parnum, [1, 0, 0, 0, 1, 0], [1, 0, 0, 0, 1, 0, 0, 0, 1])

SPRING (parnum, (0.5, 0.5, 0.0), -1, (0.5, 0.5, -1.0),
        spring = [-1, -100, 1, 100], direction = (0, 0, 1))

GRAVITY (0.0, 0.0, -10.0)

#DEM (10, 0.01)

The “DEM” command in line 25 can be uncommented to run parmec standalone and test this example:

parmec4 examples/hybrid-solver0/hs0-parmec.py

This is useful at a stage of creating and testing of an input file: the output files generated into the hybrid–solver0 directory and be viewed using ParaView.

Note

For the sake of using hs0–parmec.py as Parmec input in Solfec-1.0’s HYBRID_SOLVER, the “DEM” command in line 25 should remain commented out.

Listing 2 includes the Solfec-1.0 file hs0–solfec–1.py. SOLFEC object is created in line 3, specifying the output directory as ‘out/hybrid–solver0’ (relative where solfec is run from). Gravity is applied in line 5. Volumetric “bulk” material is created in line 7 and “suraface material” for contact interactions is created in line 10. Then the lower body “bod1” is created in line 22. This is a boundary body, coinciding with the Parmec body defined in line 16 of Listing 1. This body will be used to transfer forces between Solfec-1.0 and Parmec, and its motion will be driven by the Parmec model. The upper body “bod2” is created in line 26. In both cases Solfec-1.0’s MESH object is used to define geometry.

Listing 2 Listing of hs0–solfec–1.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
step = 0.01

sol = SOLFEC ('DYNAMIC', step, 'out/hybrid-solver0')

GRAVITY (sol, (0, 0, -10))

mat = BULK_MATERIAL (sol, model = 'KIRCHHOFF',
       young = 1, poisson = 0.25, density = 1)

SURFACE_MATERIAL (sol, model = 'SIGNORINI_COULOMB', friction = 0.1)

nodes = [0, 0, 0,
         1, 0, 0,
	 1, 1, 0,
	 0, 1, 0,
	 0, 0, 1,
	 1, 0, 1,
	 1, 1, 1,
	 0, 1, 1]

msh = HEX (nodes, 1, 1, 1, 0, [0, 1, 2, 3, 4, 5])
bod1 = BODY (sol, 'RIGID', msh, mat) # boundary bodies are rigid

FIX_DIRECTION (bod1, tuple(nodes[0:3]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[0:3]), (0, 1, 0))
FIX_DIRECTION (bod1, tuple(nodes[3:6]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[12:15]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[12:15]), (0, 1, 0))
FIX_DIRECTION (bod1, tuple(nodes[15:18]), (1, 0, 0))

msh = HEX (nodes, 2, 2, 2, 0, [0, 1, 2, 3, 4, 5])
TRANSLATE (msh, (0, 0, 1.1))
bod2 = BODY (sol, 'RIGID', msh, mat)

ns = NEWTON_SOLVER ()

# nubering of bodies in Parmec starts from 0 hence below we
# use dictionary {0 : bod1.id} as the parmec2solfec mapping
hs = HYBRID_SOLVER ('examples/hybrid-solver0/hs0-parmec.py',
                    step, {0 : bod1.id}, ns)

import solfec as solfec # this is needed since 'OUTPUT' in Solfec
solfec.OUTPUT (sol, 0.03) # collides with 'OUTPUT' in Parmec

RUN (sol, hs, 10)

The Newton solver is created next in line 28. It will be used internally by the hybrid solver in order to resolve (non–smooth) contact interactions between the two bodies. The HYBRID_SOLVER itself is created further, in line 32. We pass the full relative path to the parmec input file ‘examples/hybrid-solver0/hs0-parmec.py’, which implies that the example will be run from the solfec source directory. The Solfec-1.0 time step is used as the upper bound for the Parmec step. Knowing that Parmec numbers bodies starting from zero, we create a simple dictionary mapping, {0 : bod1.id}, to define the “boundary bodies” through which forces are passed between the two codes. Finally, we pass the Newton solver object “ns” as the last argument.

We note, that Parmec output intervals are not specified in this invocation of the hybrid solver. This means that Parmec will not create output files during the simulation. In lines 35 and 36 we define the Solfec-1.0 output interval. Because the “OUTPUT” commands coincide in both codes, we need to explicitly call the Solfec-1.0 command in this case. The input file is concluded with the “RUN” command (line 38), which executes a 10 second long simulation of the hybrid model.

The example is run by calling

solfec examples/hybrid-solver0/hs0-solfec-1.py

from within the solfec source directory. After calculations are finished, this can be followed by viewing the animated results by invoking

solfec -v examples/hybrid-solver0/hs0-solfec-1.py

An example animation is included below:

Listing 3 includes the second Solfec-1.0 file hs0–solfec–2.py. This input file demonstrates several more elaborate features of the HYBRID_SOLVER and of Solfec-1.0 input usage in general:

  • creation of Parmec output files (lines 32–36)
  • creation of Parmec time histories (lines 38–40)
  • runtime plotting from Solfec-1.0 (lines 42–51)
  • an application of matplotlib within Solfec-1.0 input file (lines 59–73)
  • XDMF export of Solfec-1.0 results (lines 75–80)
Listing 3 Listing of hs0–solfec–2.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# as in hs0-solfec-1.py
step = 0.01
sol = SOLFEC ('DYNAMIC', step, 'out/hybrid-solver0')
GRAVITY (sol, (0, 0, -10))
mat = BULK_MATERIAL (sol, model = 'KIRCHHOFF',
      young = 1, poisson = 0.25, density = 1)
SURFACE_MATERIAL (sol, model = 'SIGNORINI_COULOMB', friction = 0.1)
nodes = [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0,
         0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1]
msh = HEX (nodes, 1, 1, 1, 0, [0, 1, 2, 3, 4, 5])
bod1 = BODY (sol, 'RIGID', msh, mat) # boundary bodies are rigid
FIX_DIRECTION (bod1, tuple(nodes[0:3]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[0:3]), (0, 1, 0))
FIX_DIRECTION (bod1, tuple(nodes[3:6]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[12:15]), (1, 0, 0))
FIX_DIRECTION (bod1, tuple(nodes[12:15]), (0, 1, 0))
FIX_DIRECTION (bod1, tuple(nodes[15:18]), (1, 0, 0))
msh = HEX (nodes, 2, 2, 2, 0, [0, 1, 2, 3, 4, 5])
TRANSLATE (msh, (0, 0, 1.1))
bod2 = BODY (sol, 'RIGID', msh, mat)
ns = NEWTON_SOLVER ()

# simulation end time
stop = 10.0

# parmec's output files are written to the same
# location as the input path; for that to be the solfec's
# output directory, we copy parmec's input file there
from shutil import copyfile
copyfile('examples/hybrid-solver0/hs0-parmec.py',
         'out/hybrid-solver0/hs0-parmec.py')

# nubering of bodies in Parmec starts from 0 hence below we
# use dictionary {0 : bod1.id} as the parmec2solfec mapping
hs = HYBRID_SOLVER ('out/hybrid-solver0/hs0-parmec.py',
                    step, {0 : 1}, ns)

# parmec module becomes available
import parmec as parmec # after creation of the HYBRID_SOLVER
tms0 = parmec.TSERIES ([0, 0.03, 5, 0.03, 5+step, 0.1, stop, 0.1])
hs.parmec_interval = (tms0, 0.03) # variable output file interval
                             #and constant output history interval

# parmec time history plots are collected at runtime
t_parmec = parmec.HISTORY ('TIME')
dz_parmec = parmec.HISTORY ('DZ', 0)

# solfec time history plots at runtime
# can be collected via a callback
t_solfec = []
dz_solfec = []
def plot_callback(sol, bod):
  t_solfec.append(sol.time)
  disp = DISPLACEMENT(bod, bod.center)
  dz_solfec.append(disp[2])
  return 1
CALLBACK (sol, 0.03, (sol, bod2), plot_callback)

import solfec as solfec # this is needed since 'OUTPUT' in Solfec
solfec.OUTPUT (sol, 0.03) # collides with 'OUTPUT' in Parmec

# run simulation
RUN (sol, hs, stop)

# plot time histories
if sol.mode == 'WRITE' and not VIEWER():
  try:
    import matplotlib.pyplot as plt
    print 'Plotting time histories...'
    plt.clf ()
    plt.plot (t_parmec, dz_parmec, label = 'lower body (parmec)')
    plt.plot (t_solfec, dz_solfec, label = 'upper body (solfec)')
    plt.legend (loc = 'upper right')
    plt.xlim ((0, stop))
    plt.xlabel ('time $(s)$')
    plt.ylabel ('dz $(m)$')
    plt.savefig ('out/hybrid-solver0/hs0-dz.png')
  except:
    print 'Plotting using matplotlib has failed.'

# XDMF export
if sol.mode == 'WRITE' and not VIEWER():
  print 'Run one more times to export XDMF files!'
elif sol.mode == 'READ' and not VIEWER():
  XDMF_EXPORT (sol, (0.0, stop),
    'out/hybrid-solver0/hs0-solfec', [bod2])

When the hybrid modeling is used, the Parmec library will generate output files if the Parmec output interval has been set. Enabling this feature is demonstrated in lines 32–36, where the “parmec_interval” parameter of the hybrid solver is set to value “(tms0, 0.03)”. The “tms0” object is Parmec’s TSERIES number, which in this case defines a variable output frequency for the Parmec output files. The second number, “0.03”, defines a constant time interval, at which Parmec time histories will be generated. These are requested in the following lines 38–40. This functionality (runtime generation of time histories) is matched in Solfec-1.0 via application of a callback function, as demonstrated in lines 42–51. These time histories are later used, in lines 59–73, in order to create a plot of the vertical displacement versus time, for the lower and the upper body. The result is seen in Fig. 51.

Note

Although there is no damping in the model, some dissipative behaviour is seen in Fig. 51. This is attributed to the force transfer mechanism between the two time–stepping methods, in Solfec-1.0 and Parmec. Constant forces from the previous time step in Parmec are used over the current time step in Solfec-1.0, and vice versa. The amount of this numerical dissipation decreases with time step size.

../../../_images/hs0-dz.png

Fig. 51 Example hybrid-solver0: time histories of vertical displacement.

XDMF export is demonstrated in lines 75–80. We note, that Solfec-1.0 needs to be run for the second time, without the viewer -v parameter, in order for the actual export to occur:

solfec examples/hybrid-solver0/hs0-solfec-1.py

While Parmec output files, also in the XDMF format, are located in the ‘out/hybrid–solver0’ directory, the exported Solfec-1.0 XDMF files (.h5 and .xmf files) are placed inside of ‘out/hybrid–solver0/hs0–solfec’ directory. These files can be viewed using ParaView. An example session is depicted in Fig. 52.

../../../_images/hs0-paraview.png

Fig. 52 Example hybrid-solver0: ParaView session exploiting the generated .xmf files.