source: issm/trunk/src/m/classes/stressbalance.py@ 25836

Last change on this file since 25836 was 25836, checked in by Mathieu Morlighem, 4 years ago

merged trunk-jpl and trunk for revision 25834

File size: 11.9 KB
Line 
1import sys
2
3import numpy as np
4
5from checkfield import checkfield
6from fielddisplay import fielddisplay
7import MatlabFuncs as m
8from project3d import project3d
9from WriteData import WriteData
10
11
12class stressbalance(object):
13 """STRESSBALANCE class definition
14
15 Usage:
16 stressbalance = stressbalance()
17 """
18
19 def __init__(self): # {{{
20 self.spcvx = float('NaN')
21 self.spcvy = float('NaN')
22 self.spcvz = float('NaN')
23 self.restol = 0
24 self.reltol = 0
25 self.abstol = 0
26 self.isnewton = 0
27 self.FSreconditioning = 0
28 self.icefront = float('NaN')
29 self.maxiter = 0
30 self.shelf_dampening = 0
31 self.vertex_pairing = float('NaN')
32 self.penalty_factor = float('NaN')
33 self.rift_penalty_lock = float('NaN')
34 self.rift_penalty_threshold = 0
35 self.referential = float('NaN')
36 self.loadingforce = float('NaN')
37 self.requested_outputs = []
38
39 #set defaults
40 self.setdefaultparameters()
41
42 #}}}
43 def __repr__(self): # {{{
44 s = ' StressBalance solution parameters:\n'
45 s += ' Convergence criteria:\n'
46 s += '{}\n'.format(fielddisplay(self, 'restol', 'mechanical equilibrium residual convergence criterion'))
47 s += '{}\n'.format(fielddisplay(self, 'reltol', 'velocity relative convergence criterion, NaN: not applied'))
48 s += '{}\n'.format(fielddisplay(self, 'abstol', 'velocity absolute convergence criterion, NaN: not applied'))
49 s += '{}\n'.format(fielddisplay(self, 'isnewton', "0: Picard's fixed point, 1: Newton's method, 2: hybrid"))
50 s += '{}\n'.format(fielddisplay(self, 'maxiter', 'maximum number of nonlinear iterations'))
51 s += ' boundary conditions:\n'
52 s += '{}\n'.format(fielddisplay(self, 'spcvx', 'x - axis velocity constraint (NaN means no constraint) [m / yr]'))
53 s += '{}\n'.format(fielddisplay(self, 'spcvy', 'y - axis velocity constraint (NaN means no constraint) [m / yr]'))
54 s += '{}\n'.format(fielddisplay(self, 'spcvz', 'z - axis velocity constraint (NaN means no constraint) [m / yr]'))
55 s += '{}\n'.format(fielddisplay(self, 'icefront', 'segments on ice front list (last column 0: Air, 1: Water, 2: Ice'))
56 s = "%s\n%s" % (s, '\n Rift options:')
57 s += '{}\n'.format(fielddisplay(self, 'rift_penalty_threshold', 'threshold for instability of mechanical constraints'))
58 s += '{}\n'.format(fielddisplay(self, 'rift_penalty_lock', 'number of iterations before rift penalties are locked'))
59 s += ' Penalty options:\n'
60 s += '{}\n'.format(fielddisplay(self, 'penalty_factor', 'offset used by penalties: penalty = Kmax * 1.0**offset'))
61 s += '{}\n'.format(fielddisplay(self, 'vertex_pairing', 'pairs of vertices that are penalized'))
62 s += ' Other:\n'
63 s += '{}\n'.format(fielddisplay(self, 'shelf_dampening', 'use dampening for floating ice ? Only for FS model'))
64 s += '{}\n'.format(fielddisplay(self, 'FSreconditioning', 'multiplier for incompressibility equation. Only for FS model'))
65 s += '{}\n'.format(fielddisplay(self, 'referential', 'local referential'))
66 s += '{}\n'.format(fielddisplay(self, 'loadingforce', 'loading force applied on each point [N / m^3]'))
67 s += '{}\n'.format(fielddisplay(self, 'requested_outputs', 'additional outputs requested'))
68 return s
69 #}}}
70
71 def extrude(self, md): # {{{
72 self.spcvx = project3d(md, 'vector', self.spcvx, 'type', 'node')
73 self.spcvy = project3d(md, 'vector', self.spcvy, 'type', 'node')
74 self.spcvz = project3d(md, 'vector', self.spcvz, 'type', 'node')
75 self.referential = project3d(md, 'vector', self.referential, 'type', 'node')
76 self.loadingforce = project3d(md, 'vector', self.loadingforce, 'type', 'node')
77
78 return self
79 #}}}
80
81 def setdefaultparameters(self): # {{{
82 #maximum of non - linear iterations.
83 self.maxiter = 100
84 #Convergence criterion: absolute, relative and residual
85 self.restol = 1.0e-4
86 self.reltol = 0.01
87 self.abstol = 10
88 self.FSreconditioning = 10**13
89 self.shelf_dampening = 0
90 #Penalty factor applied kappa = max(stiffness matrix) * 1.0**penalty_factor
91 self.penalty_factor = 3
92 #Stop the iterations of rift if below a threshold
93 self.rift_penalty_threshold = 0
94 #in some solutions, it might be needed to stop a run when only
95 #a few constraints remain unstable. For thermal computation, this
96 #parameter is often used.
97 self.rift_penalty_lock = 10
98 #output default:
99 self.requested_outputs = ['default']
100 return self
101 #}}}
102
103 def defaultoutputs(self, md): # {{{
104 if md.mesh.dimension() == 3:
105 list = ['Vx', 'Vy', 'Vz', 'Vel', 'Pressure']
106 else:
107 list = ['Vx', 'Vy', 'Vel', 'Pressure']
108 return list
109 #}}}
110
111 def checkconsistency(self, md, solution, analyses): # {{{
112 # Early return
113 if 'StressbalanceAnalysis' not in analyses:
114 return md
115 if solution == 'TransientSolution' and not md.transient.isstressbalance:
116 return md
117
118 md = checkfield(md, 'fieldname', 'stressbalance.spcvx', 'Inf', 1, 'timeseries', 1)
119 md = checkfield(md, 'fieldname', 'stressbalance.spcvy', 'Inf', 1, 'timeseries', 1)
120 if m.strcmp(md.mesh.domaintype(), '3D'):
121 md = checkfield(md, 'fieldname', 'stressbalance.spcvz', 'Inf', 1, 'timeseries', 1)
122 md = checkfield(md, 'fieldname', 'stressbalance.restol', 'size', [1], '>', 0)
123 md = checkfield(md, 'fieldname', 'stressbalance.reltol', 'size', [1])
124 md = checkfield(md, 'fieldname', 'stressbalance.abstol', 'size', [1])
125 md = checkfield(md, 'fieldname', 'stressbalance.isnewton', 'numel', [1], 'values', [0, 1, 2])
126 md = checkfield(md, 'fieldname', 'stressbalance.FSreconditioning', 'size', [1], 'NaN', 1, 'Inf', 1)
127 md = checkfield(md, 'fieldname', 'stressbalance.maxiter', 'size', [1], '>=', 1)
128 md = checkfield(md, 'fieldname', 'stressbalance.referential', 'size', [md.mesh.numberofvertices, 6])
129 md = checkfield(md, 'fieldname', 'stressbalance.loadingforce', 'size', [md.mesh.numberofvertices, 3])
130 md = checkfield(md, 'fieldname', 'stressbalance.requested_outputs', 'stringrow', 1)
131 if not np.any(np.isnan(self.vertex_pairing)) and len(self.vertex_pairing) > 0:
132 md = checkfield(md, 'fieldname', 'stressbalance.vertex_pairing', '>', 0)
133 #singular solution
134 # if ~any((~isnan(md.stressbalance.spcvx) + ~isnan(md.stressbalance.spcvy)) == 2),
135 if not np.any(np.logical_and(np.logical_not(np.isnan(md.stressbalance.spcvx)), np.logical_not(np.isnan(md.stressbalance.spcvy)))):
136 print("\n !!! Warning: no spc applied, model might not be well posed if no basal friction is applied, check for solution crash\n")
137 #CHECK THAT EACH LINES CONTAINS ONLY NAN VALUES OR NO NAN VALUES
138 # if any(sum(isnan(md.stressbalance.referential), 2)~=0 & sum(isnan(md.stressbalance.referential), 2)~=6),
139 if np.any(np.logical_and(np.sum(np.isnan(md.stressbalance.referential), axis=1) != 0, np.sum(np.isnan(md.stressbalance.referential), axis=1) != 6)):
140 md.checkmessage("Each line of stressbalance.referential should contain either only NaN values or no NaN values")
141 #CHECK THAT THE TWO VECTORS PROVIDED ARE ORTHOGONAL
142 # if any(sum(isnan(md.stressbalance.referential), 2) == 0),
143 if np.any(np.sum(np.isnan(md.stressbalance.referential), axis=1) == 0):
144 pos = [i for i, item in enumerate(np.sum(np.isnan(md.stressbalance.referential), axis=1)) if item == 0]
145 # np.inner (and np.dot) calculate all the dot product permutations, resulting in a full matrix multiply
146 # if np.any(np.abs(np.inner(md.stressbalance.referential[pos, 0:2], md.stressbalance.referential[pos, 3:5]).diagonal()) > sys.float_info.epsilon):
147 # md.checkmessage("Vectors in stressbalance.referential (columns 1 to 3 and 4 to 6) must be orthogonal")
148 for item in md.stressbalance.referential[pos, :]:
149 if np.abs(np.inner(item[0:2], item[3:5])) > sys.float_info.epsilon:
150 md.checkmessage("Vectors in stressbalance.referential (columns 1 to 3 and 4 to 6) must be orthogonal")
151 #CHECK THAT NO rotation specified for FS Grounded ice at base
152 if m.strcmp(md.mesh.domaintype(), '3D') and md.flowequation.isFS:
153 pos = np.nonzero(np.logical_and(md.mask.ocean_levelset, md.mesh.vertexonbase))
154 if np.any(np.logical_not(np.isnan(md.stressbalance.referential[pos, :]))):
155 md.checkmessage("no referential should be specified for basal vertices of grounded ice")
156 return md
157 # }}}
158
159 def marshall(self, prefix, md, fid): # {{{
160
161 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'vertex_pairing', 'format', 'DoubleMat', 'mattype', 3)
162
163 yts = md.constants.yts
164
165 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'spcvx', 'format', 'DoubleMat', 'mattype', 1, 'scale', 1. / yts, 'timeserieslength', md.mesh.numberofvertices + 1, 'yts', yts)
166 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'spcvy', 'format', 'DoubleMat', 'mattype', 1, 'scale', 1. / yts, 'timeserieslength', md.mesh.numberofvertices + 1, 'yts', yts)
167 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'spcvz', 'format', 'DoubleMat', 'mattype', 1, 'scale', 1. / yts, 'timeserieslength', md.mesh.numberofvertices + 1, 'yts', yts)
168 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'restol', 'format', 'Double')
169 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'reltol', 'format', 'Double')
170 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'abstol', 'format', 'Double', 'scale', 1. / yts)
171 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'isnewton', 'format', 'Integer')
172 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'FSreconditioning', 'format', 'Double')
173 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'maxiter', 'format', 'Integer')
174 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'shelf_dampening', 'format', 'Integer')
175 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'penalty_factor', 'format', 'Double')
176 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'rift_penalty_lock', 'format', 'Integer')
177 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'rift_penalty_threshold', 'format', 'Integer')
178 WriteData(fid, prefix, 'object', self, 'class', 'stressbalance', 'fieldname', 'referential', 'format', 'DoubleMat', 'mattype', 1)
179 if isinstance(self.loadingforce, (list, tuple, np.ndarray)) and np.size(self.loadingforce, 1) == 3:
180 WriteData(fid, prefix, 'data', self.loadingforce[:, 0], 'format', 'DoubleMat', 'mattype', 1, 'name', 'md.stressbalance.loadingforcex')
181 WriteData(fid, prefix, 'data', self.loadingforce[:, 1], 'format', 'DoubleMat', 'mattype', 1, 'name', 'md.stressbalance.loadingforcey')
182 WriteData(fid, prefix, 'data', self.loadingforce[:, 2], 'format', 'DoubleMat', 'mattype', 1, 'name', 'md.stressbalance.loadingforcez')
183 # Process requested outputs
184 outputs = self.requested_outputs
185 indices = [i for i, x in enumerate(outputs) if x == 'default']
186 if len(indices) > 0:
187 outputscopy = outputs[0:max(0, indices[0] - 1)] + self.defaultoutputs(md) + outputs[indices[0] + 1:]
188 outputs = outputscopy
189 WriteData(fid, prefix, 'data', outputs, 'name', 'md.stressbalance.requested_outputs', 'format', 'StringArray')
190 # }}}
Note: See TracBrowser for help on using the repository browser.