Skip to content

Commit 1475b70

Browse files
add nutils solid participant
1 parent 3e17c0d commit 1475b70

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
. ../../tools/cleaning-tools.sh
5+
6+
clean_nutils .
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
python3 solid.py richoutput=no
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#! /usr/bin/env python3
2+
3+
from nutils import mesh, function, solver, export, cli
4+
from nutils.expression_v2 import Namespace
5+
import numpy
6+
import treelog
7+
import precice
8+
9+
10+
def main(young=4e6, density=3e3, poisson=.3, nelems=2, timestepsize=0.01, npoints_per_elem=3):
11+
12+
topo, geom = mesh.rectilinear([numpy.linspace(-.05, .05, nelems+1), numpy.linspace(0, 1, 10*nelems+1)])
13+
wall = topo.boundary['left,top,right'].sample('uniform', npoints_per_elem)
14+
15+
ns = Namespace()
16+
ns.X = geom
17+
ns.δ = function.eye(2)
18+
ns.define_for('X', gradient='∇', normal='n', jacobians=('dV', 'dS'))
19+
ns.add_field('dt')
20+
ns.add_field(('u', 'u0', 'testu', 'v', 'v0', 'testv'), topo.basis('std', degree=1), shape=(2,))
21+
ns.add_field('F', wall.basis(), shape=(2,))
22+
ns.qw = 1 / npoints_per_elem # quadrature weight
23+
ns.t_i = 'F_i / qw dS'
24+
ns.dudt_i = '(u_i - u0_i) / dt'
25+
ns.dvdt_i = '(v_i - v0_i) / dt'
26+
ns.ρ = density
27+
ns.λ = young * poisson / ((1 + poisson) * (1 - 2 * poisson))
28+
ns.μ = young / (2 * (1 + poisson))
29+
ns.σ_ij = 'λ ∇_k(u_k) δ_ij + μ (∇_j(u_i) + ∇_i(u_j))'
30+
31+
# make sure we correctly scale point forces to tractions
32+
testforce = numpy.random.normal(size=(wall.npoints, 2))
33+
numpy.testing.assert_almost_equal(
34+
actual=wall.integrate('t_i dS' @ ns, F=testforce),
35+
desired=testforce.sum(0),
36+
decimal=10,
37+
err_msg='nutils error: failed to recover net force')
38+
39+
# continuum equations: ρ v' = ∇·σ + F, u' = v
40+
res = topo.integral('testv_i (dudt_i - v_i) dV' @ ns, degree=2)
41+
res += topo.integral('(testu_i ρ dvdt_i + ∇_j(testu_i) σ_ij) dV' @ ns, degree=2)
42+
res -= wall.integral('testu_i t_i dS' @ ns)
43+
44+
# boundary conditions: fully constrained at y=0
45+
sqr = topo.boundary['bottom'].integral('u_k u_k' @ ns, degree=2)
46+
cons = solver.optimize('u,', sqr, droptol=1e-10)
47+
48+
# initial conditions: undeformed and unmoving
49+
sqr = topo.integral('u_k u_k + v_k v_k' @ ns, degree=2)
50+
arguments = solver.optimize('u,v', sqr, constrain=cons)
51+
52+
# preCICE setup
53+
solverProcessIndex = 0
54+
solverProcessSize = 1
55+
interface = precice.Interface("Solid", "../precice-config.xml", solverProcessIndex, solverProcessSize)
56+
meshID = interface.get_mesh_id("Solid-Mesh")
57+
dataIndices = interface.set_mesh_vertices(meshID, wall.eval(ns.X))
58+
writedataID = interface.get_data_id("Displacement", meshID)
59+
readdataID = interface.get_data_id("Force", meshID)
60+
61+
# initialize preCICE
62+
precice_dt = interface.initialize()
63+
64+
timestep = 0
65+
force = numpy.zeros((wall.npoints, 2))
66+
67+
while interface.is_coupling_ongoing():
68+
with treelog.context(f'timestep {timestep}'):
69+
70+
# read displacements from interface
71+
if interface.is_read_data_available():
72+
force = interface.read_block_vector_data(readdataID, dataIndices)
73+
74+
# save checkpoint
75+
if interface.is_action_required(precice.action_write_iteration_checkpoint()):
76+
checkpoint = timestep, arguments
77+
interface.mark_action_fulfilled(precice.action_write_iteration_checkpoint())
78+
79+
# advance variables
80+
timestep += 1
81+
dt = min(precice_dt, timestepsize)
82+
arguments = dict(dt=dt, u0=arguments['u'], v0=arguments['v'], F=force)
83+
arguments = solver.solve_linear('u:testu,v:testv', res, arguments=arguments, constrain=cons)
84+
85+
# write forces to interface
86+
if interface.is_write_data_required(dt):
87+
writedata = wall.eval(ns.u, **arguments)
88+
interface.write_block_vector_data(writedataID, dataIndices, writedata)
89+
90+
# do the coupling
91+
precice_dt = interface.advance(dt)
92+
93+
# read checkpoint if required
94+
if interface.is_action_required(precice.action_read_iteration_checkpoint()):
95+
timestep, arguments = checkpoint
96+
interface.mark_action_fulfilled(precice.action_read_iteration_checkpoint())
97+
98+
interface.finalize()
99+
100+
101+
if __name__ == '__main__':
102+
cli.run(main)

0 commit comments

Comments
 (0)