1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 from solvcon.gendata import SingleAssignDict, AttributeDict
20 from solvcon.anchor import Anchor
21 from solvcon.hook import BlockHook
22 from .cese import CeseSolver
23 from .cese import CeseCase
24 from .cese import CeseBC
31 """
32 BC type registry class, and its instance holds BC type classes, which can
33 be indexed by BC type name and BC type number.
34
35 In current design, there should exist only one registry singleton in
36 package.
37
38 BC classes in registry should not be altered, in any circumstances.
39 """
41 name = bctype.__name__
42 self[name] = bctype
43 return bctype
44 mltregy = MtrlTypeRegistry()
55
61 """
62 Basic elastic solver.
63
64 @ivar cfldt: the time_increment for CFL calculation at boundcond.
65 @itype cfldt: float
66 @ivar cflmax: the maximum CFL number.
67 @itype cflmax: float
68 @ivar mtrldict: map from names to material objects.
69 @itype mtrldict: dict
70 @ivar mtrllist: list of all material objects.
71 @itype mtrllist: list
72 """
73 from solvcon.dependency import getcdll
74 __clib_elastic = {
75 2: getcdll('elastic2d'),
76 3: getcdll('elastic3d'),
77 }
78 del getcdll
79 @property
82 _gdlen_ = 9 * 9 * 2
83 @property
87 self.cfldt = kw.pop('cfldt', None)
88 self.cflmax = 0.0
89 self.mtrldict = kw.pop('mtrldict', {})
90 self.mtrllist = None
91 super(ElasticSolver, self).__init__(*args, **kw)
92 @staticmethod
94 """
95 Build the material list out of the mapping dict.
96
97 @param grpnames: sequence of group names.
98 @type grpnames: list
99 @param mtrldict: the map from names to material objects.
100 @type mtrldict: dict
101 @return: the list of material object.
102 @rtype: Material
103 """
104 mtrllist = list()
105 default_mtuple = mtrldict.get(None, None)
106 for grpname in grpnames:
107 try:
108 mtrl = mtrldict.get(grpname, default_mtuple)
109 except KeyError, e:
110 args = e.args[:]
111 args.append('no material named %s in mtrldict'%grpname)
112 e.args = args
113 raise
114 mtrllist.append(mtrl)
115 return mtrllist
117 from ctypes import byref, c_int
118
119 self.mtrllist = self._build_mtrllist(self.grpnames, self.mtrldict)
120 for igrp in range(len(self.grpnames)):
121 mtrl = self.mtrllist[igrp]
122 jaco = self.grpda[igrp].reshape(self.neq, self.neq, self.ndim)
123 jaco[:,:,0] = mtrl.jacox
124 jaco[:,:,1] = mtrl.jacoy
125 if self.ndim == 3:
126 jaco[:,:,2] = mtrl.jacoz
127
128 self._set_time(self.time, self.cfldt)
129 self._clib_elastic.calc_cfl(
130 byref(self.exd), c_int(0), c_int(self.ncell))
131 self.cflmax = self.cfl.max()
132
133 super(ElasticSolver, self).provide()
135 if self.marchret is None:
136 self.marchret = [0.0, 0.0, 0, 0]
137 self.marchret[0] = self.cflmax
138 self.marchret[1] = self.cflmax
139 self.marchret[2] = 0
140 self.marchret[3] = 0
141 return self.marchret
142
148 """
149 Case for anisotropic elastic solids.
150 """
151 from solvcon.domain import Domain
152 defdict = {
153 'execution.neq': 9,
154 'solver.solvertype': ElasticSolver,
155 'solver.domaintype': Domain,
156 'solver.alpha': 0,
157 'solver.cfldt': None,
158 'solver.mtrldict': dict,
159 }
160 del Domain
170
189
191 typn = 10201
192 vnames = [
193 'bfcsys', 'tau1', 'tau2', 'tau3', 'freq', 'phase',
194 ]
195 vdefaults = {
196 'bfcsys': 0.0,
197 'tau1': 0.0, 'tau2': 0.0, 'tau3': 0.0, 'freq': 0.0, 'phase': 0.0,
198 }
199 _ghostgeom_ = 'compress'
201 from solvcon.dependency import intptr
202 from ctypes import byref, c_int
203 self._clib_boundcond.bound_traction_soln(
204 byref(self.svr.exd),
205 c_int(self.facn.shape[0]),
206 self.facn.ctypes.data_as(intptr),
207 c_int(self.value.shape[1]),
208 self.value.ctypes.data_as(self.fpptr),
209 )
211 from solvcon.dependency import intptr
212 from ctypes import byref, c_int
213 self._clib_boundcond.bound_traction_dsoln(
214 byref(self.svr.exd),
215 c_int(self.facn.shape[0]),
216 self.facn.ctypes.data_as(intptr),
217 )
218
220 typn = 10202
221 _ghostgeom_ = 'mirror'
223 from solvcon.dependency import intptr
224 from ctypes import byref, c_int
225 self._clib_boundcond.bound_traction_free_soln(
226 byref(self.svr.exd),
227 c_int(self.facn.shape[0]),
228 self.facn.ctypes.data_as(intptr),
229 )
231 from solvcon.dependency import intptr
232 from ctypes import byref, c_int
233 self._clib_boundcond.bound_traction_free_dsoln(
234 byref(self.svr.exd),
235 c_int(self.facn.shape[0]),
236 self.facn.ctypes.data_as(intptr),
237 )
238
240 typn = 10203
241 _ghostgeom_ = 'mirror'
243 from solvcon.dependency import intptr
244 from ctypes import byref, c_int
245 self._clib_boundcond.bound_traction_free2_soln(
246 byref(self.svr.exd),
247 c_int(self.facn.shape[0]),
248 self.facn.ctypes.data_as(intptr),
249 )
251 from solvcon.dependency import intptr
252 from ctypes import byref, c_int
253 self._clib_boundcond.bound_traction_free2_dsoln(
254 byref(self.svr.exd),
255 c_int(self.facn.shape[0]),
256 self.facn.ctypes.data_as(intptr),
257 )
258
264 """
265 Calculate total energy, i.e., the summation of kinetic energy and strain
266 energy.
267 """
269 from ctypes import byref
270 from numpy import empty
271 from numpy.linalg import inv
272 svr = self.svr
273
274 rhos = empty(svr.ngroup, dtype=svr.fpdtype)
275 comps = empty((svr.ngroup, 6, 6), dtype=svr.fpdtype)
276 for igp in range(svr.ngroup):
277 mtrl = svr.mtrllist[igp]
278 rhos[igp] = mtrl.rho
279 comps[igp,:,:] = inv(mtrl.stiff).T
280
281 svr._clib_elastic.calc_energy(
282 byref(svr.exd),
283 rhos.ctypes.data_as(svr.fpptr),
284 comps.ctypes.data_as(svr.fpptr),
285 svr.der['energy'].ctypes.data_as(svr.fpptr),
286 )
292 - def postfull(self):
294
300 """
301 Material properties. The constitutive relation needs not be symmetric.
302
303 @cvar _zeropoints_: list of tuples for indices where the content should be
304 zero.
305 @ctype _zeropoints_: list
306 @ivar rho: density
307 @ivar al: alpha angle.
308 @ivar be: beta angle.
309 @ivar ga: gamma angle.
310 @ivar origstiff: stiffness matrix in the crystal coordinate.
311 @ivar stiff: stiffness matrix in the transformed global coordinate.
312 """
313
314 __metaclass__ = MaterialMeta
315
316 _zeropoints_ = []
317
318 from numpy import array
319 K = array([
320 [
321 [1, 0, 0, 0, 0, 0],
322 [0, 0, 0, 0, 0, 1],
323 [0, 0, 0, 0, 1, 0],
324 ],
325 [
326 [0, 0, 0, 0, 0, 1],
327 [0, 1, 0, 0, 0, 0],
328 [0, 0, 0, 1, 0, 0],
329 ],
330 [
331 [0, 0, 0, 0, 1, 0],
332 [0, 0, 0, 1, 0, 0],
333 [0, 0, 1, 0, 0, 0],
334 ],
335 ], dtype='float64')
336 del array
337
339 from numpy import empty, dot
340 self.rho = kw.pop('rho')
341 self.al = kw.pop('al')
342 self.be = kw.pop('be')
343 self.ga = kw.pop('ga')
344
345 origstiff = empty((6,6), dtype='float64')
346 origstiff.fill(0.0)
347 for key in kw.keys():
348 if len(key) == 4 and key[:2] == 'co':
349 try:
350 i = int(key[2])-1
351 j = int(key[3])-1
352 except:
353 continue
354 assert i < origstiff.shape[0]
355 assert j < origstiff.shape[1]
356 val = kw.pop(key)
357 origstiff[i,j] = val
358 self.origstiff = origstiff
359
360 self._check_origstiffzero(self.origstiff)
361
362
363 bondmat = self.bondmat
364 self.stiff = dot(bondmat, dot(self.origstiff, bondmat.T))
365 super(Material, self).__init__(*args, **kw)
366
368 if len(key) == 4 and key[:2] == 'co':
369 i = int(key[2])
370 j = int(key[3])
371 if 1 <= i <= 6 and 1 <= j <= 6:
372 return self.origstiff[i-1,j-1]
373 elif len(key) == 3 and key[0] == 'c':
374 i = int(key[1])
375 j = int(key[2])
376 if 1 <= i <= 6 and 1 <= j <= 6:
377 return self.stiff[i-1,j-1]
378 else:
379 raise AttributeError
380
382 from math import pi
383 return '[%s: al=%.2f be=%.2f ga=%.2f (deg)]' % (self.__class__.__name__,
384 self.al/(pi/180), self.be/(pi/180), self.ga/(pi/180))
385
386 @classmethod
388 """
389 Check for zero in original stiffness matrix.
390
391 @note: no assumed symmetry.
392 """
393 for i, j in cls._zeropoints_:
394 assert origstiff[i,j] == 0.0
395
396 @property
398 """
399 Coordinate transformation matrix for three successive rotations through
400 the Euler angles.
401
402 @return: the transformation matrix.
403 @rtype: numpy.ndarray
404 """
405 from numpy import array, cos, sin, dot
406 al = self.al; be = self.be; ga = self.ga
407 almat = array([
408 [cos(al), sin(al), 0],
409 [-sin(al), cos(al), 0],
410 [0, 0, 1],
411 ], dtype='float64')
412 bemat = array([
413 [1, 0, 0],
414 [0, cos(be), sin(be)],
415 [0, -sin(be), cos(be)],
416 ], dtype='float64')
417 gamat = array([
418 [cos(ga), sin(ga), 0],
419 [-sin(ga), cos(ga), 0],
420 [0, 0, 1],
421 ], dtype='float64')
422 return dot(gamat, dot(bemat, almat))
423
424 @property
426 """
427 The Bond's matrix M as a shorthand of coordinate transformation for the
428 6-component stress vector.
429
430 @return: the Bond's matrix.
431 @rtype: numpy.ndarray
432 """
433 from numpy import empty
434 rotmat = self.rotmat
435 bond = empty((6,6), dtype='float64')
436
437 bond[:3,:3] = rotmat[:,:]**2
438
439 bond[0,3] = 2*rotmat[0,1]*rotmat[0,2]
440 bond[0,4] = 2*rotmat[0,2]*rotmat[0,0]
441 bond[0,5] = 2*rotmat[0,0]*rotmat[0,1]
442 bond[1,3] = 2*rotmat[1,1]*rotmat[1,2]
443 bond[1,4] = 2*rotmat[1,2]*rotmat[1,0]
444 bond[1,5] = 2*rotmat[1,0]*rotmat[1,1]
445 bond[2,3] = 2*rotmat[2,1]*rotmat[2,2]
446 bond[2,4] = 2*rotmat[2,2]*rotmat[2,0]
447 bond[2,5] = 2*rotmat[2,0]*rotmat[2,1]
448
449 bond[3,0] = rotmat[1,0]*rotmat[2,0]
450 bond[3,1] = rotmat[1,1]*rotmat[2,1]
451 bond[3,2] = rotmat[1,2]*rotmat[2,2]
452 bond[4,0] = rotmat[2,0]*rotmat[0,0]
453 bond[4,1] = rotmat[2,1]*rotmat[0,1]
454 bond[4,2] = rotmat[2,2]*rotmat[0,2]
455 bond[5,0] = rotmat[0,0]*rotmat[1,0]
456 bond[5,1] = rotmat[0,1]*rotmat[1,1]
457 bond[5,2] = rotmat[0,2]*rotmat[1,2]
458
459 bond[3,3] = rotmat[1,1]*rotmat[2,2] + rotmat[1,2]*rotmat[2,1]
460 bond[3,4] = rotmat[1,0]*rotmat[2,2] + rotmat[1,2]*rotmat[2,0]
461 bond[3,5] = rotmat[1,1]*rotmat[2,0] + rotmat[1,0]*rotmat[2,1]
462 bond[4,3] = rotmat[0,1]*rotmat[2,2] + rotmat[0,2]*rotmat[2,1]
463 bond[4,4] = rotmat[0,0]*rotmat[2,2] + rotmat[0,2]*rotmat[2,0]
464 bond[4,5] = rotmat[0,1]*rotmat[2,0] + rotmat[0,0]*rotmat[2,1]
465 bond[5,3] = rotmat[0,1]*rotmat[1,2] + rotmat[0,2]*rotmat[1,1]
466 bond[5,4] = rotmat[0,0]*rotmat[1,2] + rotmat[0,2]*rotmat[1,0]
467 bond[5,5] = rotmat[0,1]*rotmat[1,0] + rotmat[0,0]*rotmat[1,1]
468 return bond
469
471 """
472 @param K: the K matrix.
473 @type K: numpy.ndarray
474 @return: the Jacobian matrix in x-dir.
475 @rtype: numpy.ndarray
476 """
477 from numpy import zeros, dot
478 rho = self.rho
479 sf = self.stiff
480 jaco = zeros((9,9), dtype='float64')
481 jaco[:3,3:] = K/(-rho)
482 jaco[3:,:3] = -dot(sf, K.T)
483 return jaco
484 @property
486 """
487 @return: the Jacobian matrix in x-dir.
488 @rtype: numpy.ndarray
489 """
490 return self._jaco(self.K[0])
491 @property
493 """
494 @return: the Jacobian matrix in y-dir.
495 @rtype: numpy.ndarray
496 """
497 return self._jaco(self.K[1])
498 @property
500 """
501 @return: the Jacobian matrix in z-dir.
502 @rtype: numpy.ndarray
503 """
504 return self._jaco(self.K[2])
505
506 - def _eig(self, jaco):
507 from numpy.linalg import eig
508 evl, evc = eig(jaco)
509 srt = evl.argsort()
510 evl = evl[srt]
511 evc = evc[:,srt]
512 return evl, evc
513
514 @property
517 @property
520 @property
523
524 @property
526 return self.eigx[0][-3:]
527 @property
529 return self.eigy[0][-3:]
530 @property
532 return self.eigz[0][-3:]
533
535 """
536 The stiffness matrix has to be symmetric.
537 """
538 _zeropoints_ = []
539
541 for key in kw.keys():
542 if len(key) == 4 and key[:2] == 'co':
543 try:
544 i = int(key[2])
545 j = int(key[3])
546 except:
547 continue
548 symkey = 'co%d%d' % (j, i)
549 if i != j:
550 assert symkey not in kw
551 kw[symkey] = kw[key]
552 super(Triclinic, self).__init__(*args, **kw)
553
554 @classmethod
556 """
557 Check for zero in original stiffness matrix.
558
559 @note: assumed symmetric.
560 """
561 for i, j in cls._zeropoints_:
562 assert origstiff[i,j] == origstiff[j,i] == 0.0
563
565 _zeropoints_ = [
566 (0,3), (0,5),
567 (1,3), (1,5),
568 (2,3), (2,5),
569 (3,4), (4,5),
570 ]
571
573 _zeropoints_ = [
574 (0,3), (0,4), (0,5),
575 (1,3), (1,4), (1,5),
576 (2,3), (2,4), (2,5),
577 (3,4), (3,5), (4,5),
578 ]
579
581 _zeropoints_ = [
582 (0,3), (0,4),
583 (1,3), (1,4),
584 (2,3), (2,4), (2,5),
585 (3,4), (3,5), (4,5),
586 ]
587
589 kw['co22'] = kw['co11']
590 kw['co23'] = kw['co13']
591 kw['co26'] = -kw.get('co16', 0.0)
592 kw['co55'] = kw['co44']
593 super(Tetragonal, self).__init__(*args, **kw)
594
596 _zeropoints_ = [
597 (0,5), (1,5),
598 (2,3), (2,4), (2,5),
599 (3,4),
600 ]
601
603 kw['co15'] = -kw.get('co25', 0.0)
604 kw['co22'] = kw['co11']
605 kw['co23'] = kw['co13']
606 kw['co24'] = -kw.get('co14', 0.0)
607 kw['co46'] = kw.get('co25', 0.0)
608 kw['co55'] = kw['co44']
609 kw['co56'] = kw.get('co14', 0.0)
610 kw['co66'] = (kw['co11'] - kw['co12'])/2
611 super(Trigonal, self).__init__(*args, **kw)
612
614 _zeropoints_ = [
615 (0,3), (0,4), (0,5),
616 (1,3), (1,4), (1,5),
617 (2,3), (2,4), (2,5),
618 (3,4), (3,5), (4,5),
619 ]
620
622 _zeropoints_ = [
623 (0,3), (0,4), (0,5),
624 (1,3), (1,4), (1,5),
625 (2,3), (2,4), (2,5),
626 (3,4), (3,5), (4,5),
627 ]
628
630 kw['co13'] = kw['co12']
631 kw['co22'] = kw['co11']
632 kw['co23'] = kw['co12']
633 kw['co33'] = kw['co11']
634 kw['co55'] = kw['co44']
635 kw['co66'] = kw['co44']
636 super(Cubic, self).__init__(*args, **kw)
637
639 _zeropoints_ = [
640 (0,3), (0,4), (0,5),
641 (1,3), (1,4), (1,5),
642 (2,3), (2,4), (2,5),
643 (3,4), (3,5), (4,5),
644 ]
645
647 kw['co12'] = kw['co11']-2*kw['co44']
648 kw['co13'] = kw['co11']-2*kw['co44']
649 kw['co22'] = kw['co11']
650 kw['co23'] = kw['co11']-2*kw['co44']
651 kw['co33'] = kw['co11']
652 kw['co55'] = kw['co44']
653 kw['co66'] = kw['co44']
654 super(Isotropic, self).__init__(*args, **kw)
655
658 kw.setdefault('rho', 5307.0)
659 kw.setdefault('co11', 11.88e10)
660 kw.setdefault('co12', 5.38e10)
661 kw.setdefault('co44', 5.94e10)
662 super(GaAs, self).__init__(*args, **kw)
663
664 -class ZnO(Hexagonal):
666 kw.setdefault('rho', 5680.0)
667 kw.setdefault('co11', 20.97e10)
668 kw.setdefault('co12', 12.11e10)
669 kw.setdefault('co13', 10.51e10)
670 kw.setdefault('co33', 21.09e10)
671 kw.setdefault('co44', 4.247e10)
672 super(ZnO, self).__init__(*args, **kw)
673
674 -class CdS(Hexagonal):
676 kw.setdefault('rho', 4820.0)
677 kw.setdefault('co11', 9.07e10)
678 kw.setdefault('co12', 5.81e10)
679 kw.setdefault('co13', 5.1e10)
680 kw.setdefault('co33', 9.38e10)
681 kw.setdefault('co44', 1.504e10)
682 super(CdS, self).__init__(*args, **kw)
683
684 -class Zinc(Hexagonal):
686 kw.setdefault('rho', 7.1*1.e-3/(1.e-2**3))
687 kw.setdefault('co11', 14.3e11*1.e-5/(1.e-2**2))
688 kw.setdefault('co12', 1.7e11*1.e-5/(1.e-2**2))
689 kw.setdefault('co13', 3.3e11*1.e-5/(1.e-2**2))
690 kw.setdefault('co33', 5.0e11*1.e-5/(1.e-2**2))
691 kw.setdefault('co44', 4.0e11*1.e-5/(1.e-2**2))
692 super(Zinc, self).__init__(*args, **kw)
693
696 kw.setdefault('rho', 2.7*1.e-3/(1.e-2**3))
697 kw.setdefault('co11', 26.94e11*1.e-5/(1.e-2**2))
698 kw.setdefault('co12', 9.61e11*1.e-5/(1.e-2**2))
699 kw.setdefault('co13', 6.61e11*1.e-5/(1.e-2**2))
700 kw.setdefault('co33', 23.63e11*1.e-5/(1.e-2**2))
701 kw.setdefault('co44', 6.53e11*1.e-5/(1.e-2**2))
702 super(Beryl, self).__init__(*args, **kw)
703
706
707 kw.setdefault('co11', 69.9e9)
708 kw.setdefault('co22', 183.5e9)
709 kw.setdefault('co33', 179.5e9)
710 kw.setdefault('co44', 24.9e9)
711 kw.setdefault('co55', 26.8e9)
712 kw.setdefault('co66', 33.5e9)
713 kw.setdefault('co12', 34.0e9)
714 kw.setdefault('co13', 30.8e9)
715 kw.setdefault('co14', 5.1e9)
716 kw.setdefault('co15', -2.4e9)
717 kw.setdefault('co16', -0.9e9)
718 kw.setdefault('co23', 5.5e9)
719 kw.setdefault('co24', -3.9e9)
720 kw.setdefault('co25', -7.7e9)
721 kw.setdefault('co26', -5.8e9)
722 kw.setdefault('co34', -8.7e9)
723 kw.setdefault('co35', 7.1e9)
724 kw.setdefault('co36', -9.8e9)
725 kw.setdefault('co45', -2.4e9)
726 kw.setdefault('co46', -7.2e9)
727 kw.setdefault('co56', 0.5e9)
728 super(Albite, self).__init__(*args, **kw)
729
732 kw.setdefault('rho', 3.5e3)
733 kw.setdefault('co11', 185.8e9)
734 kw.setdefault('co22', 181.3e9)
735 kw.setdefault('co33', 234.4e9)
736 kw.setdefault('co44', 62.9e9)
737 kw.setdefault('co55', 51.0e9)
738 kw.setdefault('co66', 47.4e9)
739 kw.setdefault('co12', 68.5e9)
740 kw.setdefault('co13', 70.7e9)
741 kw.setdefault('co15', 9.8e9)
742 kw.setdefault('co23', 62.9e9)
743 kw.setdefault('co25', 9.4e9)
744 kw.setdefault('co35', 21.4e9)
745 kw.setdefault('co46', 7.7e9)
746 super(Acmite, self).__init__(*args, **kw)
747
750
751 kw.setdefault('rho', 8.2e3)
752 kw.setdefault('co11', 215.e9)
753 kw.setdefault('co22', 199.e9)
754 kw.setdefault('co33', 267.e9)
755 kw.setdefault('co44', 124.e9)
756 kw.setdefault('co55', 73.e9)
757 kw.setdefault('co66', 74.e9)
758 kw.setdefault('co12', 46.e9)
759 kw.setdefault('co13', 22.e9)
760 kw.setdefault('co23', 107.e9)
761 super(AlphaUranium, self).__init__(*args, **kw)
762
765 kw.setdefault('rho', 6.2e3)
766 kw.setdefault('co11', 275.0e9)
767 kw.setdefault('co33', 165.0e9)
768 kw.setdefault('co44', 54.3e9)
769 kw.setdefault('co66', 113.0e9)
770 kw.setdefault('co12', 179.0e9)
771 kw.setdefault('co13', 151.0e9)
772 super(BariumTitanate, self).__init__(*args, **kw)
773
776 kw.setdefault('rho', 2.651e3)
777 kw.setdefault('co11', 87.6e9)
778 kw.setdefault('co33', 106.8e9)
779 kw.setdefault('co44', 57.2e9)
780 kw.setdefault('co12', 6.1e9)
781 kw.setdefault('co13', 13.3e9)
782 kw.setdefault('co14', 17.3e9)
783 super(AlphaQuartz, self).__init__(*args, **kw)
784
787 kw.setdefault('rho', 2200.e0)
788 kw.setdefault('co11', 3200.e0**2*2200.e0)
789 kw.setdefault('co44', 1847.5e0**2*2200.e0)
790 super(RickerSample, self).__init__(*args, **kw)
793 scale = 1.e-3
794 kw.setdefault('rho', 2200.e0*scale)
795 kw.setdefault('co11', 3200.e0**2*2200.e0*scale)
796 kw.setdefault('co44', 1847.5e0**2*2200.e0*scale)
797 super(RickerSampleLight, self).__init__(*args, **kw)
798