Customizable Solver Models

Parametric Objects and Models

Python by itself provides you the ability to create parametric models. Consider the simple example below, where a spherical part is to be created. SI units are used for this example.
  1. The material is steel. Its density: rho=7800 Kg/m3
  2. The radius of the sphere is: r
  3. The mass of the sphere is: m = (4/3) * pi * r3 * rho Kg
  4. The inertia of the sphere about is center is: Ixx = Iyy = Izz = ½ * m * r2
You can create a function sphere to create a spherical part given its density rho, radius r and location loc, as follows:
def sphere (r, rho, loc, label): 
mass      = (4/3) * math.pi * (r**3) * rho
ixx       = iyy = izz = 0.5 * mass * r**2
sphere    = Part (mass=mass, ip=[ixx,iyy,izz], label=label)
sphere.cm = Marker (part=sphere, qp=loc, label=label + "_CM")
return sphere
Then you can use this function to create a parametric spherical PARTs as follows:
# Steel sphere of radius 0.1 m (10 cm)
r1   = 0.10
rho1 = 7800
loc1 = [0,10,-25]
sph1 = sphere (r1, rho1, loc1, "Steel-Sphere")
# Aluminum sphere of radius 0.05 m (5 cm)
r2   = 0.05
rho2 = 2700
loc2 = [23, 34, 45]
sph2 = sphere (r2, rho2, loc2, "Aluminum-Sphere")
The mass properties of both spheres are now parameterized in terms of their radius and density.
Important: While Python knows about this parameterization, MotionSolve does not. This is because the mass and inertia expressions are evaluated by Python and resolved into numbers and then provided to MotionSolve. If you want MotionSolve to know about the parameterization, then you need to create Designable Objects.

Designable Objects and Models

A designable object is one for which MotionSolve knows the parametric relationships. As a consequence, MotionSolve also knows how to calculate the sensitivity of any system response with respect to the design variables used to parameterize the object.

The sequence of steps required to create designable models and perform sensitivity analysis are as follows:
  1. Create design variables - this is a new class of objects recently introduced in MotionSolve.
  2. Parameterize your model using design variables.
  3. At the model level, create response variables.
  4. Perform a simulation with DSA (Design Sensitivity Analysis) turned on.
  5. MotionSolve will compute the sensitivity of the response variables to a change in the design variables. This information is made available to you in a variety of ways.
Design variables
A design variable (Dv) is an object that contains a label and value. The label is the name of the Dv, and the value is the value of the Dv. Here is an example of a design variable:
bx = Dv ( label="X coordinate of Point B", b=1.0/math.sqrt(2))
You can perform normal mathematical operations with Dvs, just as you can with numbers. Thus:
>>> bx 
<msolve.Model.Dv object at 0x0000000001F0B668>
>>> a1 = bx+bx
>>> a1
1.414213562373095 # 1/sqrt(2) + 1/sqrt(2) = sqrt(2) = 1.414213562373095
>>> a3 = bx*bx
>>> a3
0.4999999999999999 # 1/sqrt(2) * 1/sqrt(2) = 1/2
MotionSolve knows variables a1 and a3 are dependent on the design variables that bx points to.
So, now you can do parameterization with design variables and MotionSolve knows about the parametric relationships. The example below illustrates the creation of parametric spherical PARTS.
Note: You can parameterize the sphere location with design variables also. In the example below, we have not done so.
# Steel sphere of radius 0.1 m (10 cm)
r1   = Dv (label="Radius of sphere-1", b=0.10)
rho1 = Dv (label="Density of Steel", b=7800)
loc1 = [0,10,-25]
sph1 = sphere (r1, rho1, loc1, "Steel-Sphere")

# Aluminum sphere of radius 0.05 m (5 cm)
r2   = Dv (label="Radius of sphere-2", b=0.05)
rho2 = Dv (label="Density of Aluminum", b=2700)
loc2 = [23, 34, 45]
sph2 = sphere (r2, rho2, loc2, "Aluminum-Sphere")

MotionSolve knows that the mass and inertias of sph1 are dependent on r1 and rho. Similarly, it knows that the mass and inertias of sph2 are dependent on r2 and rho. Parts sph1 and sph2 are "designable".

Points and Vectors
Much of the modeling and parameterization in MotionView is done with points and vectors. The MotionSolve-Python interface supports point and vector classes. These helper classes are provided to simplify MotionSolve models and easily capture MotionView model parameterization in MotionSolve models.
Vector Class
A vector is an object that has a magnitude and a direction. In this release, vectors are always defined in the global reference frame. They do not rotate or move with any body in the model.
A vector is a list of 3 real values. Vector does not accept any other data types. It supports many methods so you can use it in a variety of ways. Here are some built-in methods for vectors.
Creating a Vector Create a copy of a Vector Indexing into a Vector
>>> u=Vector(1,2,3)
>>> u
Vector (1.0, 2.0, 3.0)
>>> v=Vector(-3,0,1)
>>> v
Vector (-3.0, 0.0, 1.0)
>>>w = u.copy()
>>> w
Vector (1.0, 2.0, 3.0)
>>> u.x 
1
>>> u.y
2
>>> u[2]
3
Unary minus Addition Subtraction
>>> -u
Vector (-1.0, -2.0, -3.0)
>>> u+v 
Vector (-2.0, 2.0, 4.0)
>>> u-v
Vector (4.0, 2.0, 2.0)
Dot Product of 2 vectors Cross Product of two vectors Angle between two vectors
>>> u%v
0
>>> u.dot(v)
0
>>> u*v 
Vector (0.169030850946, 
-0.845154254729, 
0.507092552837)
>>> u.angle(v)
1.5707963267948966
>>> u.angle(v, degrees=True)
90.0
Magnitude of a vector Create a unit vector Scale a vector with a factor
>>> u.magnitude()
3.7416573867739413
>>> u.normalize()
Vector (0.267261241912, 
0.534522483825, 
0.801783725737)
>>> u*10
Vector (10.0, 20.0, 30.0)
>>> u.scale(10)
Vector (10.0, 20.0, 30.0)
Point class
A Point is a location in space. It is represented as list of 3 real values. Point does not accept any other data types. The three values are the coordinates of the location in space with respect to some other point. Whenever operations are to be performed with points, you have to make sure all point coordinates are expressed in the same coordinate system. Point supports many methods so you can use it in a variety of ways. Here are some built-in methods for points.
Creating a Point Create a copy of a Point Indexing into a Point
>>> p=Point(1,2,3)
>>> P
Point (1.0, 2.0, 3.0)
>>> q=Vector(-3,0,1)
>>> v
Point (-3.0, 0.0, 1.0)
>>>r = p.copy()
>>> r
Point (1.0, 2.0, 3.0)
>>> u.x 
1
>>> u.y
2
>>> u[2]
3
Unary minus Addition Subtraction
>>> -P
Point (-1.0, -2.0, -3.0)
>>> p+q 
Point (-2.0, 2.0, 4.0)
>>> p-q
Point (4.0, 2.0, 2.0)
Distance between 2 points (Distance) Along Scaling
>>> p.distanceTo(q)
4.898979485566356
>>> q.distanceTo(p)
4.898979485566356
>>> p.along(q, 10) 
Point (5.08248290464, 
-2.08248290464, 
-5.16496580928)
>>> p*10
Vector (10.0, 20.0, 30.0)
>>> p.scale(10)
Vector (10.0, 20.0, 30.0

Designable Entities using Point and Vector

The location and orientations of markers can be made functions of points and vectors, and therefore, all connectivity can be made "designable". The example below illustrates.
>>> px = Dv (b=1)
>>> py = Dv (b=2)
>>> pz = Dv (b=3)
>>> p  = Point(px,py,pz)
>>> p
Point (1.0, 2.0, 3.0)

>>> #Create a Part
>>> p2 = Part (mass=1, ip=[1e-4,1e-4,1e-4])
>>> p2.cm = Marker (body=p2)

>>> #Create a designable Marker - its origin and orientation are designable
>>> p2.left = Marker (body=p2, qp=p, zp=p+[0,0,1], label="Left end")
>>> p2.left.qp
Point (1.0, 2.0, 3.0)

Now you can do Design Sensitivity Analysis with these designable MBS entities. The Python Interface has the ability to capture all reasonable MotionView parameterization in a MotionSolve model.

Finally, here is an example that shows how both PARTs and MARKERs can be made designable.
def cyl_mass_prop (l, r, rho): 
 """
   calculate mass properties of a cylinder, given
    (1) length = l
    (2) radius = r
    (3) density =rho
 """

 r2   = r*r
 l2   = l*l
 mass = math.pi * r2 * l * rho
 ixx  = iyy = mass * (3 * r2 + l2) / 12
 izz  = mass * r2 / 2
return mass, ixx, iyy, izz

# Define the design variables (Units are Kg-mm-sec-Newton)
ax  = Dv ( label="X coordinate of Point A", b=0)
ay  = Dv ( label="Y coordinate of Point A", b=0)
bx  = Dv ( label="X coordinate of Point B", b=40)
by  = Dv ( label="Y coordinate of Point B", b=200)
rad = Dv ( label="Cylinder radius", b=10)
rho = Dv ( label="Cylinder density", b=7.8E-6)

# Define the points A, B
pa  = Point (ax,ay,0) # 0, 0, 0
pb  = Point (bx,by,0) # 40, 200, 0

# Link length
lab = pa.distanceTo (pb)
# Crank: cylinder of length lab, radius=rad, density=rho
m2, ixx2, iyy2, izz2 = cyl_mass_prop (lab, rad, rho)
p2    = Part (mass=m2, ip=[ixx2, iyy2, izz2, 0, 0, 0], label="Body Crank")
qploc = (pa+pb)/2
xploc = qploc + [0,0,1]
p2.cm = Marker (body=p2, qp=qploc, zp=pb, xp=xploc, label="Crank cm marker")
In the above example:
  • Part p2 is designable - MotionSolve knows that its mass and inertia are functions of the locations of points A (defined by DVs ax, ay) and B (defined by DVs bx, by), the cylinder radius, rad, and its density, rho.
  • Similarly, the marker, p2.cm, is designable. It's location and orientation is dependent on the design variables ax, ay, bx and by.