magpar_scripts.py

Go to the documentation of this file.
00001 #################################
00002 #
00003 # magpar standard Python library
00004 #
00005 #################################
00006 
00007 # This file is part of magpar.
00008 
00009 # Copyright (C) 2010 Werner Scholz
00010 
00011 # www:   http://www.magpar.net/
00012 # email: magpar(at)magpar.net
00013 
00014 # magpar is free software; you can redistribute it and/or modify
00015 # it under the terms of the GNU General Public License as published by
00016 # the Free Software Foundation; either version 2 of the License, or
00017 # (at your option) any later version.
00018 
00019 # magpar is distributed in the hope that it will be useful,
00020 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 # GNU General Public License for more details.
00023 
00024 # You should have received a copy of the GNU General Public License
00025 # along with magpar; if not, write to the Free Software
00026 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027 
00028 import math, random, unittest, cProfile
00029 
00030 # Vector class inspired by
00031 # http://www.gamedev.net/community/forums/topic.asp?topic_id=486122
00032 
00033 # see also:
00034 #http://code.activestate.com/recipes/52272/
00035 
00036 class Vector(object):
00037     """
00038     """
00039     def __init__(self, p = [0, 0, 0]):
00040         self.x = float(p[0])
00041         self.y = float(p[1])
00042         self.z = float(p[2])
00043 
00044     def __getitem__(self, key):
00045         if(key == 0):
00046             return self.x
00047         elif(key == 1):
00048             return self.y
00049         elif(key == 2):
00050             return self.z
00051         else:
00052             raise Exception("Invalid key to Vector")
00053 
00054     def __setitem__(self, key, value):
00055         if(key == 0):
00056             self.x = value
00057         elif(key == 1):
00058             self.y = value
00059         elif(key == 2):
00060             self.z = value
00061         else:
00062             raise Exception("Invalid key to Vector")
00063 
00064     def copy(self):
00065         return Vector([self.x,self.y,self.z])
00066 
00067     def __neg__(self):
00068         return Vector([-self.x,-self.y,-self.z])
00069 
00070     def __abs__(self):
00071         return math.sqrt(self.x*self.x+self.y*self.y+self.z*self.z)
00072 
00073     def __pow__(self, val):
00074         return abs(self)**val
00075 
00076     def __add__(self, val):
00077         return Vector([self.x + val.x, self.y + val.y, self.z + val.z])
00078 
00079     def __iadd__(self, val):
00080         self.x += val.x
00081         self.y += val.y
00082         self.z += val.z
00083         return self
00084 
00085     def __sub__(self,val):
00086         return Vector([self.x - val.x, self.y - val.y, self.z - val.z])
00087 
00088     def __isub__(self, val):
00089         self.x -= val.x
00090         self.y -= val.y
00091         self.z -= val.z
00092         return self
00093 
00094     def __mul__(self, val):
00095         if type(val) == Vector:
00096           return self.x * val.x + self.y * val.y + self.z * val.z
00097         else:
00098           return Vector([self.x * val, self.y * val, self.z * val])
00099 
00100     def __rmul__(self, val):
00101         if type(val) == Vector:
00102           return self.x * val.x + self.y * val.y + self.z * val.z
00103         else:
00104           return Vector([self.x * val, self.y * val, self.z * val])
00105 
00106     def __imul__(self, val):
00107         self.x *= val
00108         self.y *= val
00109         self.z *= val
00110         return self
00111 
00112     def __div__(self, val):
00113         return Vector([self.x / val, self.y / val, self.z / val])
00114 
00115     def __idiv__(self, val):
00116         self.x /= val
00117         self.y /= val
00118         self.z /= val
00119         return self
00120 
00121     def outer(self,b):
00122         return Vector([self.y*b.z-self.z*b.y,
00123                        self.z*b.x-self.x*b.z,
00124                        self.x*b.y-self.y*b.x])
00125 
00126     def normalize(self):
00127         if abs(self)<1e-9:
00128             self.x = 0.0
00129             self.y = 0.0
00130             self.z = 0.0
00131         else:
00132             l = abs(self)
00133             self.x /= l
00134             self.y /= l
00135             self.z /= l
00136         return self
00137 
00138     def __eq__(self,other):
00139         if (self.x==other.x) & (self.y==other.y) & (self.z==other.z):
00140             return True
00141         else:
00142             return False
00143 
00144     def __ne__(self,other):
00145         return not(self==other)
00146 
00147     def __repr__(self):
00148         return "[" + str(self.x) + "," + str(self.y) + "," + str(self.z) + "]"
00149 
00150     def __str__(self):
00151         return "(" + str(self.x) + "," + str(self.y) + "," + str(self.z) + ")"
00152 
00153 class TestVectorClass(unittest.TestCase):
00154     def setUp(self):
00155         self.x=Vector([1,0,0])
00156         self.y=Vector([0,1,0])
00157         self.z=Vector([0,0,1])
00158         self.a=Vector([3,0,0])
00159         self.b=Vector([0,4,0])
00160         self.c=Vector([3,4,0])
00161 
00162     def testNeg(self):
00163         t = self.c.copy()
00164         t = -t
00165         self.assertEqual(t,Vector([-3,-4,0]))
00166 
00167     def testAbs(self):
00168         t=abs(self.a)
00169         self.assertEqual(t,3.0)
00170         t=abs(self.c)
00171         self.assertEqual(t,5.0)
00172 
00173     def testPow(self):
00174         t=self.a**2.0
00175         self.assertEqual(t,abs(self.a)**2.0)
00176         t=abs(self.c)
00177         self.assertEqual(t,5.0)
00178 
00179     def testSimpleArithmetics(self):
00180         t = self.x+self.y
00181         self.assertEqual(t,Vector([1,1,0]))
00182         t -= self.y
00183         self.assertEqual(t,self.x)
00184         t = self.x - self.y
00185         self.assertEqual(t,Vector([1,-1,0]))
00186         t += self.y
00187         self.assertEqual(t,self.x)
00188         t = self.x * 3.0
00189         self.assertEqual(t,self.a)
00190         t /= 3.0
00191         self.assertEqual(t,self.x)
00192         t = self.a / 3.0
00193         self.assertEqual(t,self.x)
00194         t *= 3.0
00195         self.assertEqual(t,self.a)
00196         t = self.x * self.a
00197         self.assertEqual(t,3.0)
00198 
00199     def testOuter(self):
00200         t=self.x.outer(self.y)
00201         self.assertEqual(t,self.z)
00202 
00203     def testNormalize(self):
00204         t=self.a.normalize()
00205         self.assertEqual(t,self.x)
00206 
00207 def initialize_magnetization_mx(r):
00208     """
00209     """
00210     return Vector([1.0, 0.0, 0.0])
00211 
00212 def initialize_magnetization_my(r):
00213     """
00214     """
00215     return Vector([0.0, 1.0, 0.0])
00216 
00217 def initialize_magnetization_mz(r):
00218     """
00219     """
00220     return Vector([0.0, 0.0, 1.0])
00221 
00222 def initialize_magnetization_111(r):
00223     """
00224     """
00225     a=math.sqrt(1.0/3.0)
00226     return Vector([a, a, a])
00227 
00228 def initialize_magnetization_theta_rad(r, theta = 0):
00229     """Set magnetization in x-z plane to desired angle theta (from z-axis)
00230     """
00231 
00232     return Vector([math.sin(theta), 0.0, math.cos(theta)])
00233 
00234 def initialize_magnetization_theta_deg(r, theta_deg = 0):
00235     m = initialize_magnetization_theta_rad(r,math.radians(theta_deg))
00236 
00237     return m
00238 
00239 def initialize_magnetization_phi_rad(r, phi = 0):
00240     """Set magnetization in x-y plane to desired angle
00241     """
00242 
00243     return Vector([math.cos(theta), math.sin(theta), 0.0])
00244 
00245 def initialize_magnetization_phi_deg(r,phi_deg = 0):
00246     m = initialize_magnetization_phi_rad(r,math.radians(phi_deg))
00247 
00248     return m
00249 
00250 def initialize_magnetization_random(r):
00251     """Random magnetization - inaccurate: not uniform on unit sphere!
00252     """
00253 
00254     mx = random.uniform(-1, 1)
00255     my = random.uniform(-1, 1)
00256     mz = random.uniform(-1, 1)
00257 
00258     return Vector([mx, my, mz])
00259 
00260 def initialize_magnetization_flower(r, c = Vector([0.0,0.0,0.0]), f = 1.0):
00261     """Approximate flower state (around z-axis)
00262     """
00263 
00264     m = Vector([r[0]-c[0],r[1]-c[1],1.0])
00265     if (r[2]<0):
00266         m *= -1.0
00267 
00268     return m
00269 
00270 def vortex(p, R):
00271     """Approximate vortex state
00272 
00273     vortex centered at (cx, cy) with radius R:
00274     if R>0, then vortex is counter-clockwise in xy plane.
00275     if R<0, then vortex is clockwise in xy plane.
00276     center of vortex points in pol*z direction.
00277     """
00278 
00279     r=p.copy()
00280     r[2]=0
00281     absr=abs(r)
00282 
00283     # inside vortex core
00284     if absr <= math.fabs(R):
00285         A = 2.0*R*absr/(R*R+absr*absr)
00286         # avoid division by zero
00287         if (absr > 1e-8):
00288             m = Vector([A*r[1]/absr, -A*r[0]/absr, pol*math.sqrt(1.0-A*A)])
00289         else:
00290             m = Vector([0.0, 0.0, pol])
00291     # outside vortex core
00292     else:
00293         m = Vector([r[1]/absr, -r[0]/absr, 0.0])
00294 
00295     if R<0:
00296         m[0]=-m[0]
00297         m[1]=-m[1]
00298 
00299     return m
00300 
00301 def initialize_magnetization_vortex(r, c = Vector([0.0,0.0,0.0])):
00302     """Approximate vortex state
00303     """
00304 
00305     # vortex radius
00306     R = 0.1
00307 
00308     # polarity (+1.0 or -1.0)
00309     pol = 1.0
00310 
00311     m = vortex(r-c, R)
00312     m[2] *= pol
00313 
00314     return Vector(m)
00315 
00316 def initialize_magnetization_blochwall(r, xpos = 0.0, width = 0.1):
00317     """Bloch wall (parallel to y-z plane)
00318     """
00319 
00320     if (r[0] < xpos-width/2.0):
00321         m = Vector([0.0, 0.0, -1.0])
00322     elif (r[0] > xpos+width/2.0):
00323         m = Vector([0.0, 0.0, 1.0])
00324     else:
00325         m = Vector([0.0,
00326                     math.cos((r[0]-xpos)/(width/2.0)*(math.pi/2.0)),
00327                     math.sin((r[0]-xpos)/(width/2.0)*(math.pi/2.0))])
00328 
00329     return m
00330 
00331 def initialize_magnetization_head_to_head_transverse(x, y, z, xpos = 0.0, width = 0.1):
00332     """Transverse head-to-head wall
00333     """
00334 
00335     if (r[0] < xpos-width/2.0):
00336         m = Vector([1.0, 0.0, 0.0])
00337     elif (r[0] > xpos+width/2.0):
00338         m = Vector([-1.0, 0.0, 0.0])
00339     else:
00340         m = Vector([-math.sin((x-xpos)/(width/2.0)*(math.pi/2.0)),
00341                     math.cos((x-xpos)/(width/2.0)*(math.pi/2.0)),
00342                     0.0])
00343 
00344     return m
00345 
00346 def initialize_magnetization_head_to_head_vortex(r, xpos = 0.0, width = 0.1):
00347     """Approximate vortex head-to-head wall
00348 
00349     Head-to-head vortex wall at (0, 0) with radius R
00350     if R>0, then vortex is clockwise in xy plane.
00351     if R<0, then vortex is counter-clockwise in xy plane.
00352     center of vortex points in -z direction.
00353     """
00354 
00355     if (x < xpos-width/2.0):
00356         m = Vector([1.0, 0.0, 0.0])
00357     elif (x > xpos+width/2.0):
00358         m = Vector([-1.0, 0.0, 0.0])
00359     else:
00360         m = vortex(r-c, R)
00361         m[2] *= pol
00362 
00363     return m
00364 
00365 def external_field_homogeneous(r, theta_deg = 0.0, phi_deg = 0.0, amp_T = 0.0):
00366     """
00367     """
00368 
00369     theta = math.radians(theta_deg)
00370     phi   = math.radians(phi_deg)
00371 
00372     h = Vector([amp_T*math.sin(theta)*math.cos(phi),
00373                 amp_T*math.sin(theta)*math.sin(phi),
00374                 amp_T*math.cos(theta)])
00375 
00376     return h
00377 
00378 def external_field_time_scaling(t_ns):
00379     """
00380     """
00381 
00382     if (t_ns<0):
00383         amp_T=0
00384     else:
00385         amp_T=t_ns
00386 
00387     return amp_T
00388 
00389 class Line:
00390     def __init__(self,a,b):
00391       self.start_point = a
00392       self.end_point = b
00393       self.vector = b-a
00394       self.length = abs(b-a)
00395 
00396     def __str__(self):
00397         return "start_point: " + str(self.start_point) + "\n" + \
00398                "end_point:   " + str(self.end_point) + "\n"  + \
00399                "vector:      " + str(self.vector) + "\n"  + \
00400                "length:      " + str(self.length) + "\n"
00401 
00402 class TestLineClass(unittest.TestCase):
00403     def setUp(self):
00404         self.a=Vector([3,0,0])
00405         self.b=Vector([0,4,0])
00406         self.line=Line(self.a,self.b)
00407 
00408     def testvector(self):
00409         self.assertEqual(self.line.vector,Vector([-3,4,0]))
00410 
00411     def testlength(self):
00412         self.assertEqual(self.line.length,5)
00413 
00414 class Segment:
00415     def __init__(self,s,a,b):
00416       self.start = s
00417       self.line = Line(a,b)
00418 
00419     def __str__(self):
00420         return "start: " + str(self.start) + "\n" + str(self.line)
00421 
00422 class Polygon:
00423     def __init__(self):
00424         self.segments = []
00425         self.length = 0.0
00426 
00427     def append_segment(self,a,b):
00428         self.segments.append(Segment(self.length,a,b))
00429         self.length += abs(b-a)
00430 
00431     def point(self,u):
00432         for s in self.segments:
00433             if (u>=s.start/self.length) & (u<(s.start+s.line.length)/self.length):
00434                 p = s.line.start_point + (u-s.start/self.length)*s.line.vector/s.line.length*self.length
00435                 return p
00436 
00437     def vec(self,u,length):
00438         for s in self.segments:
00439             if (u>=s.start/self.length) & (u<(s.start+s.line.length)/self.length):
00440                 v = Vector(s.line.vector)
00441                 v.normalize()
00442                 return v*length
00443 
00444     def __str__(self):
00445         string = "Polygon of length " + str(self.length) + \
00446                  " with " + str(len(self.segments)) + " segments\n"
00447         for s in self.segments:
00448             string += str(s)
00449         return string
00450 
00451 def test_straight_poly():
00452     poly_points=[]
00453     poly_points.append(Vector([-100.0,0.0,0.0]))
00454     poly_points.append(Vector([ -50.0,0.0,0.0]))
00455     poly_points.append(Vector([ -10.0,0.0,0.0]))
00456     poly_points.append(Vector([   0.0,0.0,0.0]))
00457     poly_points.append(Vector([   5.0,0.0,0.0]))
00458     poly_points.append(Vector([  30.0,0.0,0.0]))
00459     poly_points.append(Vector([ 100.0,0.0,0.0]))
00460     polygon = Polygon()
00461     for s in range(len(poly_points)-1):
00462         polygon.append_segment(poly_points[s],poly_points[s+1])
00463     return polygon
00464 
00465 class TestPolygonClass(unittest.TestCase):
00466     def setUp(self):
00467         self.polygon = test_straight_poly()
00468 
00469     def testpoints(self):
00470         self.assertEqual(self.polygon.point(0),self.polygon.segments[0].line.start_point)
00471         self.assertEqual(self.polygon.length,200)
00472         self.assertEqual(self.polygon.point(0.5),Vector([0,0,0]))
00473         self.assertEqual(self.polygon.point(0.99),Vector([98,0,0]))
00474         self.assertEqual(self.polygon.vec(0,1),Vector([1,0,0]))
00475 
00476 def biot_savart(current_A, r, ds):
00477     """Calculate magnetic field according to Biot-Savart law
00478 
00479     dB=mu0*I/(4 pi)* (ds x r)/r^3
00480 
00481     http://en.wikipedia.org/wiki/Biot-Savart_law
00482     http://maxwell.byu.edu/~spencerr/websumm122/node70.html
00483     http://hyperphysics.phy-astr.gsu.edu/HBASE/magnetic/magcur.html#c2
00484     """
00485 
00486 #    if abs(r) < abs(ds)*5.0:
00487 #        print "Warning: distance r ", abs(r), r, " too short compared to segment ds ", abs(ds), ds
00488 
00489     if abs(r)<1e-9:
00490         # catch 1/r divergence
00491         h = Vector([0,0,0])
00492     else:
00493         h = 1e-7*current_A*ds.outer(r)/abs(r)**3.0
00494     return h
00495 
00496 class TestBiotSavart(unittest.TestCase):
00497     def setUp(self):
00498         self.polygon = test_straight_poly()
00499 
00500     def testfield(self):
00501         h=biot_savart(1.0, Vector([0,0,1]), Vector([0.01,0,0]))
00502         self.assertAlmostEqual(abs(h)*1e9,1,5)
00503         h.normalize()
00504         self.assertEqual(h,Vector([0,-1,0]))
00505 
00506 def field_of_wire_slow(wire,current_A,r):
00507     npoints=10000
00508     h = Vector()
00509     for u in range(0,npoints):
00510         #print wire.point(u*1.0/npoints), wire.vec(u*1.0/npoints,wire.length/npoints), r
00511         h += biot_savart(current_A, \
00512                     wire.point(u*1.0/npoints)-r, \
00513                     wire.vec(u*1.0/npoints,wire.length/npoints))
00514     return h
00515 
00516 def field_of_wire(wire,current_A,r):
00517     npoints=1000
00518     h = Vector()
00519     for s in wire.segments:
00520         for u in range(0,npoints):
00521             h += biot_savart(current_A, \
00522                         s.line.start_point+s.line.vector*u/npoints-r, \
00523                         s.line.vector/npoints)
00524     return h
00525 
00526 class Test_external_field_wire(unittest.TestCase):
00527     def setUp(self):
00528         self.polygon = test_straight_poly()
00529 
00530     # http://hyperphysics.phy-astr.gsu.edu/HBASE/magnetic/magcur.html#c2
00531     def testfield(self):
00532         h = field_of_wire_slow(self.polygon,1.0,Vector([0,0,0.1]))
00533 
00534         self.assertAlmostEqual(abs(h)*1e7,20,4)
00535         h.normalize()
00536         self.assertEqual(h,Vector([0,1,0]))
00537 
00538 def initmag(x, y, z):
00539     """Initialize magnetization with desired function called in here.
00540 
00541     This function must be define after all the initialize_magnetization_* functions!
00542     """
00543 
00544     r = Vector([x,y,z])
00545     m = initialize_magnetization_mx(r)
00546 
00547     m /= abs(m)
00548 
00549     return m[0],m[1],m[2]
00550 
00551 def hext_xyz2(x, y, z):
00552     """Set external field with desired function called in here.
00553 
00554     This function must be define after all the external_field_* functions!
00555     """
00556 
00557     h_T = external_field_homogeneous(x, y, z)
00558 
00559     return h_T[0], h_T[1], h_T[2]
00560 
00561 def hext_xyzt(x, y, z, t_ns):
00562     """Set external field with desired function called in here.
00563 
00564     This function must be define after all the external_field_* functions!
00565     """
00566 
00567     h_T = external_field_homogeneous(x, y, z)
00568     f = external_field_time_scaling(t_ns)
00569 
00570     return h_T[0]*f, h_T[1]*f, h_T[2]*f
00571 
00572 # Finally, import user defined functions.
00573 # These can shadow/overload the standard functions above!
00574 
00575 #from magpar_user_scripts import *
00576 
00577 # from: http://www.python.org/doc/essays/list2str.html
00578 import time
00579 def timing(f, n, a):
00580     print f.__name__,
00581     r = range(n)
00582     t1 = time.clock()
00583     for i in r:
00584         f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a); f(a)
00585     t2 = time.clock()
00586     print round(t2-t1, 3)
00587 
00588 def test_function_2col():
00589     astart = -3.0
00590     astop = 3.0
00591     nstep = 100
00592 
00593     for i in range(nstep+1):
00594         a = astart+i*(astop-astart)/nstep
00595 
00596         # v1, v2, v3 = initialize_magnetization_flower(a, 0, 0)
00597         v1 = hext_xyzt(0,0,0,a)
00598 
00599         print a, v1
00600 
00601 def misc3():
00602     import matplotlib.pyplot as plt
00603     plt.plotfile("x",cols=(0,1),delimiter=" ")
00604 
00605 def wire_z():
00606     poly_points=[]
00607     poly_points.append(Vector([0.0,0.0, -10.0]))
00608     poly_points.append(Vector([0.0,0.0,  10.0]))
00609     polygon = Polygon()
00610     for s in range(len(poly_points)-1):
00611         polygon.append_segment(poly_points[s],poly_points[s+1])
00612     return polygon
00613 
00614 def hext_f(t_ns):
00615     """
00616     """
00617 
00618     tstart = 0.0
00619     fstart = 0.0
00620     tend   = 50.0
00621     fend   = 200.0
00622 
00623     if t_ns < t_start:
00624         f=fstart
00625     elif t_ns < fend:
00626         f=fstart+(fend-fstart)*(t_ns-tstart)/(tend-tstart)
00627 
00628     return f
00629 
00630 coils = wire_z()
00631 
00632 def hext_xyz(x, y, z):
00633     """Set external field with desired function called in here.
00634 
00635     This function must be defined after all the external_field_* functions!
00636     """
00637 
00638     h_T = field_of_wire(coils,0.001,Vector([x,y,z]))
00639 
00640     return h_T[0], h_T[1], h_T[2]
00641 
00642 # http://docs.python.org/tutorial/modules.html#executing-modules-as-scripts
00643 if __name__ == "__main__":
00644     #test_function_2col()
00645 
00646     #print hext_xyz(1.0,0,0)
00647     cProfile.run('print hext_xyz(1.0,0,0)')
00648 
00649     unittest.main()

magpar - Parallel Finite Element Micromagnetics Package
Copyright (C) 2002-2010 Werner Scholz