forked from timovanopstal/sambal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnonlin.py
146 lines (104 loc) · 4.65 KB
/
nonlin.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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
from nutils import *
##########################################
# Newton-Raphson solver #
##########################################
class NewtonSolver( object ):
def __init__ ( self, system, state=None ):
self.system = system
def solve ( self, rtol, maxiter=25, atol=1e-12, **linearsolverargs ):
cons = self.system.get_total_cons()-self.system.state
residual, tangent = self.system.get_residual_and_tangent()
for iiter in log.range( 'Newton iterations', maxiter ):
self.system.state += tangent.solve( -residual, constrain=cons, **linearsolverargs )
residual, tangent = self.system.get_residual_and_tangent()
rnorm = numpy.linalg.norm(residual[~cons.where])
if iiter == 0: #Predictor step
rscale = rnorm
log.info( 'Predictor residual: %5.4e' % rscale )
rnorm = 1. if rscale > atol else 0.
cons&=0
else: #Corrector steps
rnorm = (1./rscale)*rnorm
log.info( 'Iteration %d: %5.4e' % (iiter,rnorm) )
if rnorm < rtol:
break
else:
log.error('Newton solver did not converge in %d iterations' % maxiter )
return 0
##########################################
# Partitioned solver #
##########################################
class PartitionedSolver( object ):
def __init__ ( self, system, doforder, state=None ):
self.system = system
self.doforder = doforder
assert all(field in self.system.dofgroups for field in doforder)
def solve ( self, **linearsolverargs ):
for ifield in self.doforder:
#Select the subproblem
log.info( 'Solving subproblem "%s" with %d DOFs' % (ifield,len(self.system.dofgroups[ifield])) )
#Get the constraints for the current subproblem
icons = getattr( self.system, 'get_total_cons_' + ifield )()
#Constrain all the dofs that are not in the current subproblem
for jfield in self.doforder:
if ifield == jfield:
continue
jdofs = self.system.dofgroups[jfield]
icons[list(jdofs)] = self.system.state[list(jdofs)]
#Get the lhs and rhs for the current subproblem
ilhs, irhs = getattr( self.system, 'get_residual_and_tangent_' + ifield)()
#Solve the subproblem
self.system.state = ilhs.solve( rhs=irhs, constrain=icons, **linearsolverargs )
return True
##########################################
# System base class #
##########################################
class System ( object ):
def __init__ ( self, size, state=None ):
if state is not None:
assert state.ndim==1 and state.size==size
else:
state = numpy.zeros( size )
self.state = state
def solve ( self, solver=NewtonSolver, **kwargs ):
return solver( self ).solve( **kwargs )
if __name__ == "__main__":
#######################################
# Nonlinear beam #
#######################################
class NonlinearBeamSystem ( System ):
def __init__ ( self, topo, geom, funcsp, E, I, A, q, size ):
super(NonlinearBeamSystem, self).__init__( size )
self.topo = topo
self.geom = geom
self.funcsp = funcsp
self.EI = E*I
self.EA = E*A
self.q = q
def rfunc ( self ):
w = funcsp.dot( self.state )
return self.EI*w.laplace(geom)*self.funcsp.laplace(geom) + 3./2.*self.EA*(w.grad(geom)[0]**3)*self.funcsp.grad(geom)[:,0]-self.q*self.funcsp
def tanfunc ( self ):
w = funcsp.dot( self.state )
return self.EI*function.outer(self.funcsp.laplace(geom)) + 9./2.*self.EA*(w.grad(geom)[0]**2)*function.outer(self.funcsp.grad(geom)).sum(-1)
def get_residual ( self ):
return self.topo.integrate( self.rfunc(self.state), geometry=self.geom, ischeme='gauss3' )
def get_tangent ( self ):
return self.topo.integrate( self.tanfunc(self.state), geometry=self.geom, ischeme='gauss3' )
def get_residual_and_tangent ( self ):
return self.topo.integrate( [self.rfunc(),self.tanfunc()], geometry=self.geom, ischeme='gauss3' )
def get_total_cons ( self ):
cons = self.topo.boundary['left'].project( 0, onto=self.funcsp, geometry=self.geom, ischeme='gauss1' )
cons |= self.topo.boundary['left'].project( 0, onto=self.funcsp.grad(geom)[:,0], geometry=self.geom, ischeme='gauss1' )
return cons
L = 1.
q = 4.
E = 1.
A = 1.
I = 1.
n = 10
topo, geom = mesh.rectilinear([numpy.linspace(0,L,n+1)])
funcsp = topo.splinefunc( degree=2 )
system = NonlinearBeamSystem( topo=topo, geom=geom, funcsp=funcsp, E=E, I=I, A=A, q=q, size=funcsp.size )
system.solve( rtol=1e-6 )
log.info( 'Tip deflection: %4.3f (%4.3f)' % (system.state[-1],q*L**4/(8.*E*I)) )