DynamicRelaxation backend

Using the compas.numerical.DynamicRelaxation() solver with the default backend works for me:

dr = DynamicRelaxation()

xyz, q, f, l, r = dr(vertices, edges, fixed, loads, qpre, fpre,
                     lpre, linit, E, radius, kmax=100,
                     callback=callback)

However, switching to the numpy backend by writing dr = DynamicRelaxation(backend='numpy') dose not work and I get the following message:

Message: global name 'array' is not defined

Traceback:
  line 225, in dr_numpy, "C:\Users\sehlstro\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\compas\numerical\dr\dr_numpy.py"
  line 136, in __call__, "C:\Users\sehlstro\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\compas\numerical\dr\__init__.py"
  line 130, in <module>, "C:\Users\sehlstro\Desktop\planartripod.py"

Im am running my script in IronPython in Rhino 5.0 on a Windows 10 computer.

that makes sense because the numpy backend is not directly available for Rhino (since numpy is not available for ironpython). will post an example showing how to use an xfunc for that…

Aha. That makes sense.

I guess it’s just to do the same way as explained for the force density method here then?

https://compas-dev.github.io/main/api/generated/compas.utilities.XFunc.html

Naa, it was not that easy. Writing:

dr = XFunc('compas.numerical.dr.dr_numpy')

xyz, q, f, l, r = dr(vertices, edges, fixed, loads, qpre, fpre,
                     lpre, linit, E, radius, kmax=100,
                     callback=callback)

Gives

Message: <function callback at 0x0000000000001646> is not JSON serializable

Traceback:
  line 436, in _iterencode, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\encoder.py"
  line 402, in _iterencode_dict, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\encoder.py"
  line 402, in _iterencode_dict, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\encoder.py"
  line 428, in _iterencode, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\encoder.py"
  line 178, in default, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\encoder.py"
  line 26, in default, "C:\Users\sehlstro\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\compas\utilities\encoders.py"
  line 181, in dump, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\json\__init__.py"
  line 343, in __call__, "C:\Users\sehlstro\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\compas\utilities\xfunc.py"
  line 134, in <module>, "C:\Users\sehlstro\Desktop\planartripod.py"

almost, though. the docs are a bit behind the code on that point. the multi-backend wrappers are fairly new…

import random

import compas
from compas.datastructures import Mesh
from compas.utilities import XFunc
from compas_rhino.artists import MeshArtist

dr = XFunc('compas.numerical.dr.dr_numpy.dr_numpy')

dva = {
    'is_fixed': False,
    'x': 0.0,
    'y': 0.0,
    'z': 0.0,
    'px': 0.0,
    'py': 0.0,
    'pz': 0.0,
    'rx': 0.0,
    'ry': 0.0,
    'rz': 0.0,
}

dea = {
    'qpre': 1.0,
    'fpre': 0.0,
    'lpre': 0.0,
    'linit': 0.0,
    'E': 0.0,
    'radius': 0.0,
}

mesh = Mesh.from_obj(compas.get('faces.obj'))

mesh.update_default_vertex_attributes(dva)
mesh.update_default_edge_attributes(dea)

for key, attr in mesh.vertices(True):
    attr['is_fixed'] = mesh.vertex_degree(key) == 2

for u, v, attr in mesh.edges(True):
    attr['qpre'] = 1.0 * random.randint(1, 7)

k_i = mesh.key_index()

vertices = mesh.get_vertices_attributes(('x', 'y', 'z'))
edges    = [(k_i[u], k_i[v]) for u, v in mesh.edges()]
fixed    = [k_i[key] for key in mesh.vertices_where({'is_fixed': True})]
loads    = mesh.get_vertices_attributes(('px', 'py', 'pz'))
qpre     = mesh.get_edges_attribute('qpre')
fpre     = mesh.get_edges_attribute('fpre')
lpre     = mesh.get_edges_attribute('lpre')
linit    = mesh.get_edges_attribute('linit')
E        = mesh.get_edges_attribute('E')
radius   = mesh.get_edges_attribute('radius')

xyz, q, f, l, r = dr(vertices, edges, fixed, loads, qpre, fpre, lpre, linit, E, radius, kmax=100)

for key, attr in mesh.vertices(True):
    index = k_i[key]
    attr['x'] = xyz[index][0]
    attr['y'] = xyz[index][1]
    attr['z'] = xyz[index][2]

artist = MeshArtist(mesh, layer="XFunc::Mesh")

artist.clear_layer()

artist.draw_vertices()
artist.draw_edges()
artist.draw_faces()

artist.redraw()

Unfortunately callbacks don’t work with XFuncs , yet…

Running your example still gives me an error:

Message: WindowsError

Traceback:
  line 669, in __init__, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\subprocess.py"
  line 877, in _execute_child, "C:\Program Files (x86)\Rhinoceros 5\Plug-ins\IronPython\Lib\subprocess.py"
  line 362, in __call__, "C:\Users\sehlstro\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\compas\utilities\xfunc.py"
  line 56, in <module>, "C:\Users\sehlstro\AppData\Local\Temp\TempScript.py"

save the script after copying the snippet into the script editor in rhino. the error says you don’t have write access to the temp folder for writing the serialisation files. this happens if your script is still a TempScript.py.

alternatively you could specify an absolute path to a specific folder for writing the serialisation files:

dr = XFunc('compas.numerical.dr.dr_numpy.dr_numpy', tmpdir='path/to/some/folder/')