Working with Shapes and Regions

I’ve introduced an easy-to-use high-level interface for working with shapes and regions. There are a number of built-in elementary shapes (rectangle, disk, triangle, ellipsoid, torus, pyramid, tetrahedron, cone) which can be combined to form composite shapes. These shapes can then be used as 1) physical objects in meshes, 2) as masks to set magnetization directions, and 3) as regions to set material parameter values. The shapes also have transformation functions, including scaling, translation, rotation, array generation.

Shapes can be used directly with console commands, however the best way to use them is with the high-level Python interface now provided through the NetSocks.py module. Let’s have a look at some examples.

First let’s take a simple example with two objects: a torus and a disk.

from NetSocks import NSClient
from NetSocks import Shape

ns = NSClient('localhost', serverport = 1542)
ns.configure(True)

########################################

l, w, t = 800e-9, 800e-9, 100e-9
ns.meshrect([l, w, t])
ns.delrect()

tor = Shape.torus([l, w, t])
disk = Shape.disk([l/2, w/2, t])

#set disk centred
ns.shape_set(disk.move([l/2, w/2, t/2]))
#set torus centred
ns.shape_set(tor.move([l/2, w/2, t/2]))

#set magnetization angles of defined shapes
ns.shape_setangle(disk, [180, 0])
ns.shape_setangle(tor, [90, 90])

The Shape class contains all the elementary shapes, which can be combined using simple operators (+, -) into composite shapes. Once a shape is define it can be physically set in the mesh using theĀ shape_set function. The shapes can also be used as masks to set magnetization angle using theĀ shape_setangle function. The above example produces the following mesh structure and magnetization direction:

Finally the shapes can be used to define regions with different material parameters, set using the shape_setparam function.

#set material parameter values of regions defined by shapes
ns.setparam(ns.meshfocus(), 'Ms', 1)
ns.shape_setparam('Ms', disk, 600e3)
ns.shape_setparam('Ms', tor, 1200e3)

If we look at the Ms material parameter spatial variation we have the following:

All material parameters in Boris may be assigned a spatial variation with the same resolution as the mesh discretization, and there are a number of built-in spatial variation generators as described in the manual. Internally this is handled efficiently (in terms of code reuse and maintainability, as well as execution time) using a variadic template function to check material parameters spatial, temporal, and temperature dependences.

Let’s have a look at a more advanced example. First let’s set a hollow half-torus, and set its left and right sides to different magnetization directions, using the following script:

from NetSocks import NSClient
from NetSocks import Shape

ns = NSClient('localhost', serverport = 1542)
ns.configure(True)

########################################

l, w, t = 800e-9, 800e-9, 200e-9
ns.meshrect([l, w, t])
ns.cellsize([2.5e-9, 2.5e-9, 2.5e-9])
ns.delrect()

#define hollow half-torus
tor1 = Shape.torus([l, w, t])
tor2 = Shape.torus([l - t/2 + t*0.75/2, w - t/2 + t*0.75/2, t*0.75])
htor = tor1 - tor2 - Shape.rect([l, w/2, t]).move([0, -w/4, 0])

#define masks for left and right sides of half-torus
left = htor - Shape.rect([l/2, w/2, t]).move([l/4, w/4, 0])
right = htor - Shape.rect([l/2, w/2, t]).move([-l/4, w/4, 0])

#set shape and magnetization directions for left and right sides
ns.shape_set(htor.move([l/2, w/2, t/2]))
ns.shape_setangle(left.move([l/2, w/2, t/2]), [90, 90])
ns.shape_setangle(right.move([l/2, w/2, t/2]), [90, 270])

This produces the following:

Let’s take it a step further and introduce more shapes, also showing how rotations and array generation can be used:

#rectangular base
base = Shape.rect([l * 0.6, w*0.5, 10e-9])
ns.shape_set(base.move([l/2, w/4, t/3]))

#repeated tetrahedra
d = 40e-9
tetra = Shape.tetrahedron([d, d, d])
tetra.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
ns.shape_set(tetra.move([l * 0.2 + d, d, t/3 + d/2]))
ns.shape_setangle(tetra, [90, 0])

#repeated pyramids
pyramid = Shape.pyramid([d, d, d])
pyramid.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
ns.shape_set(pyramid.move([l * 0.2 + 3*d, d, t/3 + d/2]))
ns.shape_setangle(pyramid, [0, 0])

#repeated rotated triangles
triangle = Shape.triangle([d, d, d])
triangle.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
triangle.rotate([0, 90, 45])
ns.shape_set(triangle.move([l * 0.2 + 5*d, d, t/3 + d/2]))
ns.shape_setangle(triangle, [180, 0])

#repeated rotated excentric tubes
tube = Shape.disk([d, d, d]) - Shape.disk([d/2, d/2, d]).move([d/5, 0, 0])
tube.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
tube.rotate([-30, 45, 45])
ns.shape_set(tube.move([l * 0.2 + 7*d, d, t/3 + d/2]))
ns.shape_setangle(tube, [90, 90])

#repeated ellipsoids
ellipsoid = Shape.ellipsoid([d/2, d*1.5, d*0.75])
ellipsoid.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
ns.shape_set(ellipsoid.move([l * 0.2 + 9*d, d, t/3 + d/2]))
ns.shape_setangle(ellipsoid, [90, 270])

#repeated cones
cone = Shape.cone([d, d, d])
cone.setrepetitions([1, w / (4*d), 1], [0, d * 2, 0])
ns.shape_set(cone.move([l * 0.2 + 11*d, d, t/3 + d/2]))
ns.shape_setangle(cone, [45, 45])

This now produces the following:

Finally let’s relax the magnetization so it looks a bit more interesting (why not!):

This functionality will be available in v3.0, which I’m hoping to release this Friday.