diff --git a/CHANGELOG.md b/CHANGELOG.md index d1efb001dd73..159d7d509e00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `compas.datastructures.VolMesh.from_meshgrid`. * Added `vertices_where`, `vertices_where_predicate`, `edges_where`, `edges_where_predicate` to `compas.datastructures.HalfFace`. * Added `faces_where`, `faces_where_predicate`, `cells_where`, `cells_where_predicate` to `compas.datastructures.HalfFace`. +* Added `3.1` to supported versions for Blender installer. ### Changed @@ -33,10 +34,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Changed `compas_ghpython.artists.MeshArtist.draw_vertexlabels` to use the colors of the vertex color dict. * Changed `compas_ghpython.artists.MeshArtist.draw_edgelabels` to use the colors of the edge color dict. * Changed `compas_ghpython.artists.MeshArtist.draw_facelabels` to use the colors of the face color dict. +* Fixed `compas_blender.uninstall`. +* Changed `planarity` to optional requirement on all platforms. +* Changed `numba` to optional requirement on all platforms. * Changed raw github content path for `compas.get`. ### Removed +* Removed `compas.numerical.drx`. + ## [1.14.1] 2022-02-16 diff --git a/docs/conf.py b/docs/conf.py index 7f9190dbbfae..4c45186e7c28 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -74,7 +74,7 @@ def patched_m2r2_setup(app): "sphinx.ext.graphviz", "matplotlib.sphinxext.plot_directive", "m2r2", - "nbsphinx", + # "nbsphinx", "sphinx.ext.autodoc.typehints", "tabs" ] diff --git a/requirements-dev.txt b/requirements-dev.txt index 0e82e934440f..f2b50db3505d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -12,7 +12,7 @@ isort m2r2 nbsphinx pydocstyle -pytest >=3.2 +pytest <7.1 sphinx_compas_theme >=0.15.18 sphinx >=3.4 twine diff --git a/requirements.txt b/requirements.txt index d83fa22847eb..0ebdb89aeb73 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,10 +10,10 @@ matplotlib >= 2.2, < 3.1; python_version >= '3.5' and python_version <= '3.7' an matplotlib >= 3.1; python_version >= '3.8' and sys_platform == 'win32' matplotlib >= 2.2; python_version >= '3.5' and sys_platform != 'win32' networkx -numba +# numba numpy >= 1.15.4 pillow -planarity ; sys_platform != 'win32' +# planarity ; sys_platform != 'win32' pycollada schema scipy >= 1.1 diff --git a/setup.py b/setup.py index f2245a0cde50..421564eda1b4 100644 --- a/setup.py +++ b/setup.py @@ -67,6 +67,7 @@ def read(*names, **kwargs): python_requires='>=2.7', extras_require={ 'planarity': ['planarity'], + 'numba': ['numba'] }, entry_points={ 'console_scripts': [ diff --git a/src/compas/numerical/drx/__init__.py b/src/compas/numerical/drx/__init__.py deleted file mode 100644 index 95727a8987b9..000000000000 --- a/src/compas/numerical/drx/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -import compas - -if not compas.IPY: - from .drx_numpy import * # noqa: F401 F403 - -if not compas.IPY: - from .drx_numba import * # noqa: F401 F403 - - -__all__ = [name for name in dir() if not name.startswith('_')] diff --git a/src/compas/numerical/drx/drx_numba.py b/src/compas/numerical/drx/drx_numba.py deleted file mode 100644 index b5a92be44d35..000000000000 --- a/src/compas/numerical/drx/drx_numba.py +++ /dev/null @@ -1,377 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from numpy import arccos -from numpy import array -from numpy import isnan -from numpy import mean -from numpy import sin -from numpy import sqrt -from numpy import sum -from numpy import zeros - -from numba import guvectorize -from numba import f8 -from numba import i4 -from numba import i8 - -from numba import jit - -try: - from numba import prange -except ImportError: - prange = range - -from compas.numerical import uvw_lengths - -from compas.numerical.drx.drx_numpy import _beam_data -from compas.numerical.drx.drx_numpy import _create_arrays - -# from compas_hpc.geometry import cross_vectors_numba as cross -# from compas_hpc.geometry import dot_vectors_numba as dot -# from compas_hpc.geometry import length_vector_numba as length - -from time import time - - -__all__ = [ - 'drx_numba', -] - - -@jit(f8(f8[:]), nogil=True, nopython=True, parallel=False, cache=True) -def length(a): - """Calculate the length of a vector. - - Parameters - ---------- - a : array - XYZ components of the vector. - - Returns - ------- - float: The length of the vector. - """ - return sqrt(a[0]**2 + a[1]**2 + a[2]**2) - - -@jit(f8(f8[:], f8[:]), nogil=True, nopython=True, parallel=False, cache=True) -def dot(u, v): - """Compute the dot product of two vectors. - - Parameters - ---------- - u : array - XYZ components of the first vector. - v : array - XYZ components of the second vector. - - Returns - ------- - float - u . v. - """ - return u[0] * v[0] + u[1] * v[1] + u[2] * v[2] - - -@jit(f8[:](f8[:], f8[:]), nogil=True, nopython=True, parallel=False, cache=True) -def cross(u, v): - """Compute the cross product of two vectors. - - Parameters - ---------- - u : array - XYZ components of the first vector. - v : array - XYZ components of the second vector. - - Returns - ------- - array - u X v. - """ - w = zeros(3) - w[0] = u[1] * v[2] - u[2] * v[1] - w[1] = u[2] * v[0] - u[0] * v[2] - w[2] = u[0] * v[1] - u[1] * v[0] - return w - - -def _args(network, factor, summary, steps, tol): - X, B, P, S, V, E, A, C, Ct, f0, l0, ind_c, ind_t, u, v, M, k0, m, n, rows, cols, vals, nv = _create_arrays(network) - inds, indi, indf, EIx, EIy, beams = _beam_data(network) - if not ind_c: - ind_c = [-1] - if not ind_t: - ind_t = [-1] - ind_c = array(ind_c) - ind_t = array(ind_t) - return tol, steps, summary, m, n, u, v, X, f0, l0, k0, ind_c, ind_t, B, P, S, rows, cols, vals, nv, M, factor, V, inds, indi, indf, EIx, EIy, beams, C - - -def drx_numba(network, factor=1.0, tol=0.1, steps=10000, summary=0, update=False): - """ Run Numba accelerated dynamic relaxation analysis. - - Parameters - ---------- - network : obj - Network to analyse. - factor : float - Convergence factor. - tol : float - Tolerance value. - steps : int - Maximum number of steps. - summary : int - Print summary at end (1:yes or 0:no). - update : bool - Update the co-ordinates of the Network. - - Returns - ------- - array - Vertex co-ordinates. - array - Edge forces. - array - Edge lengths. - """ - # Setup - tic1 = time() - args = _args(network, factor, summary, steps, tol) - toc1 = time() - tic1 - - # Solver - tic2 = time() - tol, steps, summary, m, n, u, v, X, f0, l0, k0, ind_c, ind_t, B, P, S, rows, cols, vals, nv, M, factor, V, inds, indi, indf, EIx, EIy, beams, C = args - drx_solver_numba(tol, steps, summary, m, n, u, v, X, f0, l0, k0, ind_c, ind_t, B, P, S, rows, cols, vals, nv, - M, factor, V, inds, indi, indf, EIx, EIy, beams) - _, l = uvw_lengths(C, X) # noqa: E741 - f = f0 + k0 * (l.ravel() - l0) - toc2 = time() - tic2 - - # Summary - if summary: - print('\n\nNumba DR -------------------') - print('Setup time: {0:.3f} s'.format(toc1)) - print('Solver time: {0:.3f} s'.format(toc2)) - print('----------------------------------') - - # Update - if update: - k_i = network.key_index() - uv_i = network.uv_index() - for key in network.vertices(): - x, y, z = X[k_i[key], :] - network.set_vertex_attributes(key, 'xyz', [x, y, z]) - for uv in network.edges(): - i = uv_i[uv] - network.set_edge_attribute(uv, 'f', float(f[i])) - - return X, f, l - - -@guvectorize([(f8, i8, i8, i8, i8, i4[:], i4[:], f8[:, :], f8[:], f8[:], f8[:], i8[:], i8[:], f8[:, :], f8[:, :], - f8[:, :], i4[:], i4[:], f8[:], i8, f8[:], f8, f8[:, :], i4[:], i4[:], i4[:], f8[:], f8[:], i8, f8)], - '(),(),(),(),(),(m),(m),(n,p),(m),(m),(m),(a),(b),(n,p),(n,p),(n,p),(c),(c),(c),(),(n),(),(n,p),(k),(k),(k),(k),(k),()->()', - nopython=True, cache=True, target='parallel') -def drx_solver_numba(tol, steps, summary, m, n, u, v, X, f0, l0, k0, ind_c, ind_t, B, P, S, rows, cols, vals, nv, - M, factor, V, inds, indi, indf, EIx, EIy, beams, out): - """Numba accelerated dynamic relaxation solver. - - Parameters - ---------- - tol : float - Tolerance value. - steps : int - Maximum number of steps. - summary : int - Print summary 1 or 0. - m : int - Number of edges. - n : int - Number of vertices. - u : array - Network edges' start points. - v : array - Network edges' end points. - X : array - Nodal co-ordinates. - f0 : array - Initial edge forces. - l0 : array - Initial edge lengths. - k0 : array - Initial edge axial stiffnesses. - ind_c : array - Indices of compression only edges. - ind_t : array - Indices of tension only edges. - B : array - Constraint conditions Bx, By, Bz. - P : array - Nodal loads Px, Py, Pz. - S : array - Shear forces Sx, Sy, Sz. - rows : array - Edge adjacencies (rows). - cols : array - Edge adjacencies (columns). - vals : array - Edge adjacencies (values). - nv : int - Length of rows, cols and vals. - M : array - Mass matrix. - factor : float - Convergence factor. - V : array - Nodal velocities. - inds : array - Indices of beam element start nodes. - indi : array - Indices of beam element intermediate nodes. - indf : array - Indices of beam element finish nodes beams. - EIx : array - Nodal EIx flexural stiffnesses. - EIy : array - Nodal EIy flexural stiffnesses. - beams : int - Beam analysis on: 1 or off: 0. - """ - f = zeros(m) - fx = zeros(m) - fy = zeros(m) - fz = zeros(m) - frx = zeros(n) - fry = zeros(n) - frz = zeros(n) - Rn = zeros(n) - Una = zeros(n) - - res = 1000 * tol - ts, Uo = 0, 0 - - while (ts <= steps) and (res > tol): - - for i in range(m): - xd = X[v[i], 0] - X[u[i], 0] - yd = X[v[i], 1] - X[u[i], 1] - zd = X[v[i], 2] - X[u[i], 2] - l = sqrt(xd**2 + yd**2 + zd**2) # noqa: E741 - f[i] = f0[i] + k0[i] * (l - l0[i]) - q = f[i] / l - fx[i] = xd * q - fy[i] = yd * q - fz[i] = zd * q - - if ind_t[0] != -1: - for i in ind_t: - if f[i] < 0: - fx[i] = 0 - fy[i] = 0 - fz[i] = 0 - - if ind_c[0] != -1: - for i in ind_c: - if f[i] > 0: - fx[i] = 0 - fy[i] = 0 - fz[i] = 0 - - if beams: - S *= 0 - for i in range(len(inds)): - Xs = X[inds[i], :] - Xi = X[indi[i], :] - Xf = X[indf[i], :] - Qa = Xi - Xs - Qb = Xf - Xi - Qc = Xf - Xs - Qn = cross(Qa, Qb) - - mu = 0.5 * (Xf - Xs) - La = length(Qa) - Lb = length(Qb) - Lc = length(Qc) - LQn = length(Qn) - Lmu = length(mu) - - a = arccos((La**2 + Lb**2 - Lc**2) / (2 * La * Lb)) - k = 2 * sin(a) / Lc - ex = Qn / LQn - ez = mu / Lmu - ey = cross(ez, ex) - - K = k * Qn / LQn - Kx = dot(K, ex) * ex - Ky = dot(K, ey) * ey - Mc = EIx[i] * Kx + EIy[i] * Ky - cma = cross(Mc, Qa) - cmb = cross(Mc, Qb) - ua = cma / length(cma) - ub = cmb / length(cmb) - c1 = cross(Qa, ua) - c2 = cross(Qb, ub) - Lc1 = length(c1) - Lc2 = length(c2) - Ms = Mc[0]**2 + Mc[1]**2 + Mc[2]**2 - - Sa = ua * Ms * Lc1 / (La * dot(Mc, c1)) - Sb = ub * Ms * Lc2 / (Lb * dot(Mc, c2)) - - if isnan(Sa).any() or isnan(Sb).any(): - pass - else: - S[inds[i], :] += Sa - S[indi[i], :] -= Sa + Sb - S[indf[i], :] += Sb - - frx *= 0 - fry *= 0 - frz *= 0 - - for i in range(nv): - frx[rows[i]] += vals[i] * fx[cols[i]] - fry[rows[i]] += vals[i] * fy[cols[i]] - frz[rows[i]] += vals[i] * fz[cols[i]] - - for i in range(n): - Rx = (P[i, 0] - S[i, 0] - frx[i]) * B[i, 0] - Ry = (P[i, 1] - S[i, 1] - fry[i]) * B[i, 1] - Rz = (P[i, 2] - S[i, 2] - frz[i]) * B[i, 2] - Rn[i] = sqrt(Rx**2 + Ry**2 + Rz**2) - - Mi = M[i] * factor - V[i, 0] += Rx / Mi - V[i, 1] += Ry / Mi - V[i, 2] += Rz / Mi - Una[i] = Mi * (V[i, 0]**2 + V[i, 1]**2 + V[i, 2]**2) - - Un = sum(Una) - - if Un < Uo: - V *= 0 - Uo = Un - - # X += V - for i in range(n): - X[i, 0] += V[i, 0] - X[i, 1] += V[i, 1] - X[i, 2] += V[i, 2] - - res = mean(Rn) - - # # refresh - # if refresh: - # if (ts % refresh == 0) or (res < tol): - # print('Step:{0} Residual:{1:.3f}'.format(ts, res)) - # if callback: - # callback(X, **kwargs) - - ts += 1 - - if summary: - print('Step:', ts - 1, ' Residual:', res) diff --git a/src/compas/numerical/drx/drx_numpy.py b/src/compas/numerical/drx/drx_numpy.py deleted file mode 100644 index efa68aac7447..000000000000 --- a/src/compas/numerical/drx/drx_numpy.py +++ /dev/null @@ -1,334 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function - -from numpy import arccos -from numpy import array -from numpy import cross -from numpy import float64 -from numpy import int32 -from numpy import isnan -from numpy import mean -from numpy import newaxis -from numpy import sin -from numpy import sum -from numpy import tile -from numpy import zeros - -from scipy.sparse import find - -from compas.numerical import connectivity_matrix -from compas.numerical import mass_matrix -from compas.numerical import normrow -from compas.numerical import uvw_lengths - -from time import time - - -__all__ = ['drx_numpy'] - - -def drx_numpy(structure, factor=1.0, tol=0.1, steps=10000, refresh=100, update=False, callback=None, **kwargs): - """Run dynamic relaxation analysis. - - Parameters - ---------- - structure : compas.datastructures.Datastructure - The structure to analyse. - factor : float - Convergence factor. - tol : float - Tolerance value. - steps : int - Maximum number of steps. - refresh : int - Update progress every nth step. - update : bool - Update the co-ordinates of the Network. - callback : callable - Callback function. - - Returns - ------- - array - Vertex co-ordinates. - array - Edge forces. - array - Edge lengths. - - Examples - -------- - >>> - """ - # Setup - tic1 = time() - X, B, P, S, V, E, A, C, Ct, f0, l0, ind_c, ind_t, u, v, M, k0, m, n, rows, cols, vals, nv = _create_arrays(structure) - inds, indi, indf, EIx, EIy, beams = _beam_data(structure) - EIx = EIx.reshape(-1, 1) - EIy = EIy.reshape(-1, 1) - toc1 = time() - tic1 - - # Solver - tic2 = time() - X, f, l = drx_solver_numpy(tol, steps, factor, C, Ct, X, M, k0, l0, f0, ind_c, ind_t, P, S, B, V, refresh, # noqa: E741 - beams, inds, indi, indf, EIx, EIy, callback, **kwargs) - toc2 = time() - tic2 - - # Summary - if refresh: - print('\n\nNumPy-SciPy DR -------------------') - print('Setup time: {0:.3f} s'.format(toc1)) - print('Solver time: {0:.3f} s'.format(toc2)) - print('----------------------------------') - - # Update - if update: - k_i = structure.key_index() - for key in structure.nodes(): - i = k_i[key] - structure.node_attributes(key, 'xyz', X[i]) - uv_i = structure.uv_index() - for uv in structure.edges(): - i = uv_i[uv] - structure.edge_attribute(uv, 'f', float(f[i])) - - return X, f, l, structure - - -def drx_solver_numpy(tol, steps, factor, C, Ct, X, M, k0, l0, f0, ind_c, ind_t, P, S, B, V, refresh, - beams, inds, indi, indf, EIx, EIy, callback, **kwargs): - """NumPy and SciPy dynamic relaxation solver. - - Parameters - ---------- - tol : float - Tolerance value. - steps : int - Maximum number of steps. - factor : float - Convergence factor. - C : array - Connectivity matrix. - Ct : array - Transposed connectivity matrix. - X : array - Nodal co-ordinates. - M : array - Mass matrix. - k0 : array - Initial edge axial stiffnesses. - l0 : array - Initial edge lengths. - f0 : array - Initial edge forces. - ind_c : list - Indices of compression only edges. - ind_t : list - Indices of tension only edges. - P : array - Nodal loads Px, Py, Pz. - S : array - Shear forces Sx, Sy, Sz. - B : array - Constraint conditions Bx, By, Bz. - V : array - Nodal velocities Vx, Vy, Vz. - refresh : int - Update progress every n steps. - beams : int - Beam data flag 1 or 0. - inds : array - Indices of beam element start nodes. - indi : array - Indices of beam element intermediate nodes. - indf : array - Indices of beam element finish nodes beams. - EIx : array - Nodal EIx flexural stiffnesses. - EIy : array - Nodal EIy flexural stiffnesses. - callback : obj - Callback function. - - Returns - ------- - array - Vertex co-ordinates. - array - Edge forces. - array - Edge lengths. - """ - res = 1000 * tol - ts, Uo = 0, 0 - M = factor * tile(M.reshape((-1, 1)), (1, 3)) - - while (ts <= steps) and (res > tol): - - uvw, l = uvw_lengths(C, X) # noqa: E741 - f = f0 + k0 * (l.ravel() - l0) - - if ind_t: - f[ind_t] *= f[ind_t] > 0 - if ind_c: - f[ind_c] *= f[ind_c] < 0 - - if beams: - S = _beam_shear(S, X, inds, indi, indf, EIx, EIy) - - q = f[:, newaxis] / l - qt = tile(q, (1, 3)) - R = (P - S - Ct.dot(uvw * qt)) * B - res = mean(normrow(R)) - - V += R / M - Un = sum(M * V**2) - if Un < Uo: - V *= 0 - Uo = Un - - X += V - - if refresh: - if (ts % refresh == 0) or (res < tol): - print('Step:{0} Residual:{1:.3f}'.format(ts, res)) - if callback: - callback(X, **kwargs) - - ts += 1 - - return X, f, l - - -def _beam_data(structure): - if structure.attributes.get('beams', None): - inds, indi, indf, EIx, EIy = [], [], [], [], [] - for beam in structure.attributes['beams'].values(): - nodes = beam['nodes'] - inds.extend(nodes[:-2]) - indi.extend(nodes[1:-1]) - indf.extend(nodes[2:]) - EIx.extend([structure.node_attribute(i, 'EIx') for i in nodes[1:-1]]) - EIy.extend([structure.node_attribute(i, 'EIy') for i in nodes[1:-1]]) - inds = array(inds, dtype=int32) - indi = array(indi, dtype=int32) - indf = array(indf, dtype=int32) - EIx = array(EIx, dtype=float64) - EIy = array(EIy, dtype=float64) - beams = 1 - else: - inds = indi = indf = array([0], dtype=int32) - EIx = EIy = array([0.], dtype=float64) - beams = 0 - - print(indf) - - return inds, indi, indf, EIx, EIy, beams - - -def _beam_shear(S, X, inds, indi, indf, EIx, EIy): - S *= 0 - Xs = X[inds, :] - Xi = X[indi, :] - Xf = X[indf, :] - Qa = Xi - Xs - Qb = Xf - Xi - Qc = Xf - Xs - Qn = cross(Qa, Qb) - mu = 0.5 * (Xf - Xs) - La = normrow(Qa) - Lb = normrow(Qb) - Lc = normrow(Qc) - LQn = normrow(Qn) - Lmu = normrow(mu) - a = arccos((La**2 + Lb**2 - Lc**2) / (2 * La * Lb)) - k = 2 * sin(a) / Lc - ex = Qn / tile(LQn, (1, 3)) - ez = mu / tile(Lmu, (1, 3)) - ey = cross(ez, ex) - K = tile(k / LQn, (1, 3)) * Qn - Kx = tile(sum(K * ex, 1)[:, newaxis], (1, 3)) * ex - Ky = tile(sum(K * ey, 1)[:, newaxis], (1, 3)) * ey - Mc = EIx * Kx + EIy * Ky - cma = cross(Mc, Qa) - cmb = cross(Mc, Qb) - ua = cma / tile(normrow(cma), (1, 3)) - ub = cmb / tile(normrow(cmb), (1, 3)) - c1 = cross(Qa, ua) - c2 = cross(Qb, ub) - Lc1 = normrow(c1) - Lc2 = normrow(c2) - Ms = sum(Mc**2, 1)[:, newaxis] - Sa = ua * tile(Ms * Lc1 / (La * sum(Mc * c1, 1)[:, newaxis]), (1, 3)) - Sb = ub * tile(Ms * Lc2 / (Lb * sum(Mc * c2, 1)[:, newaxis]), (1, 3)) - Sa[isnan(Sa)] = 0 - Sb[isnan(Sb)] = 0 - S[inds, :] += Sa - S[indi, :] -= Sa + Sb - S[indf, :] += Sb - return S - - -def _create_arrays(structure): - # Vertices - n = structure.number_of_nodes() - B = zeros((n, 3), dtype=float64) - P = zeros((n, 3), dtype=float64) - X = zeros((n, 3), dtype=float64) - S = zeros((n, 3), dtype=float64) - V = zeros((n, 3), dtype=float64) - k_i = structure.key_index() - for key in structure.nodes(): - i = k_i[key] - B[i, :] = structure.node_attribute(key, 'B') - P[i, :] = structure.node_attribute(key, 'P') - X[i, :] = structure.node_attributes(key, 'xyz') - - # Edges - m = structure.number_of_edges() - u = zeros(m, dtype=int32) - v = zeros(m, dtype=int32) - E = zeros(m, dtype=float64) - A = zeros(m, dtype=float64) - s0 = zeros(m, dtype=float64) - l0 = zeros(m, dtype=float64) - ind_c = [] - ind_t = [] - uv_i = structure.uv_index() - for key in structure.edges(): - i = uv_i[key] - E[i] = structure.edge_attribute(key, 'E') - A[i] = structure.edge_attribute(key, 'A') - if structure.edge_attribute(key, 'l0'): - l0[i] = structure.edge_attribute(key, 'l0') - else: - l0[i] = structure.edge_length(*key) - if structure.edge_attribute(key, 's0'): - s0[i] = structure.edge_attribute(key, 's0') - else: - s0[i] = 0 - u[i] = k_i[key[0]] - v[i] = k_i[key[1]] - ct = structure.edge_attribute(key, 'ct') - if ct == 'c': - ind_c.append(i) - elif ct == 't': - ind_t.append(i) - f0 = s0 * A - k0 = E * A / l0 - q0 = f0 / l0 - - print(k0) - - # Other - C = connectivity_matrix([[k_i[i], k_i[j]] for i, j in structure.edges()], 'csr') - Ct = C.transpose() - M = mass_matrix(Ct=Ct, ks=k0, q=q0, c=1, tiled=False) - rows, cols, vals = find(Ct) - rows = array(rows, dtype=int32) - cols = array(cols, dtype=int32) - vals = array(vals, dtype=float64) - nv = vals.shape[0] - - return X, B, P, S, V, E, A, C, Ct, f0, l0, ind_c, ind_t, u, v, M, k0, m, n, rows, cols, vals, nv diff --git a/src/compas_blender/__init__.py b/src/compas_blender/__init__.py index b56413d7ca7f..bedd750f5fb1 100644 --- a/src/compas_blender/__init__.py +++ b/src/compas_blender/__init__.py @@ -55,7 +55,7 @@ def redraw(): def _check_blender_version(version): - supported_versions = ['2.83', '2.93'] + supported_versions = ['2.83', '2.93', '3.1'] if not version: return '2.93' diff --git a/src/compas_blender/install.py b/src/compas_blender/install.py index 109384cf942d..3401a89432f3 100644 --- a/src/compas_blender/install.py +++ b/src/compas_blender/install.py @@ -53,7 +53,7 @@ def install(blender_path, version=None): The path to the folder with the version number of Blender. For example, on Mac: ``'/Applications/Blender.app/Contents/Resources/2.83'``. On Windows: ``'%PROGRAMFILES%/Blender Foundation/Blender 2.83/2.83'``. - version : {'2.83', '2.93'}, optional + version : {'2.83', '2.93', '3.1'}, optional The version number of Blender. Default is ``'2.93'``. @@ -151,7 +151,7 @@ def install(blender_path, version=None): parser = argparse.ArgumentParser() parser.add_argument('blenderpath', nargs='?', help="The path to the folder with the version number of Blender.") - parser.add_argument('-v', '--version', choices=['2.83', '2.93'], help="The version of Blender to install COMPAS in.") + parser.add_argument('-v', '--version', choices=['2.83', '2.93', '3.1'], help="The version of Blender to install COMPAS in.") args = parser.parse_args() diff --git a/src/compas_blender/uninstall.py b/src/compas_blender/uninstall.py index 3125053816da..97e4d7548d7c 100644 --- a/src/compas_blender/uninstall.py +++ b/src/compas_blender/uninstall.py @@ -1,22 +1,28 @@ import os import sys +import compas from compas._os import remove from compas._os import remove_symlink from compas._os import rename +import compas_blender + __all__ = ['uninstall'] -def uninstall(blender_path): +def uninstall(blender_path, version=None): """Uninstall COMPAS from Blender. Parameters ---------- blender_path : str The path to the folder with the version number of Blender. - For example, on Mac: ``'/Applications/blender.app/Contents/Resources/2.80'``. - On Windows: ``'%PROGRAMFILES%\\Blender Foundation\\Blender\\2.80'``. + For example, on Mac: ``'/Applications/Blender.app/Contents/Resources/2.83'``. + On Windows: ``'%PROGRAMFILES%/Blender Foundation/Blender 2.83/2.83'``. + version : {'2.83', '2.93', '3.1'}, optional + The version number of Blender. + Default is ``'2.93'``. Examples -------- @@ -29,6 +35,23 @@ def uninstall(blender_path): print('Conda environment not found. The installation into Blender requires an active conda environment with a matching Python version to continue.') sys.exit(-1) + if not version and not blender_path: + version = '2.93' + + if version and blender_path: + print('Both options cannot be provided simultaneously. Provide the full installation path, or the version with flag -v.') + sys.exit(-1) + + if version: + if compas.LINUX: + print('Version-based installs are currently not supported for Linux. Please provide the full installation path with the -p option.') + sys.exit(-1) + + blender_path = compas_blender._get_default_blender_installation_path(version) + + if not os.path.exists(blender_path): + raise FileNotFoundError('Blender version folder not found.') + path, version = os.path.split(blender_path) print('Uninstalling COMPAS for Blender {}'.format(version)) @@ -65,7 +88,9 @@ def uninstall(blender_path): parser = argparse.ArgumentParser() - parser.add_argument('versionpath', help="The path to the folder with the version number of Blender.") + parser.add_argument('blenderpath', nargs='?', help="The path to the folder with the version number of Blender.") + parser.add_argument('-v', '--version', choices=['2.83', '2.93', '3.1'], help="The version of Blender to install COMPAS in.") + args = parser.parse_args() - uninstall(args.versionpath) + uninstall(args.blenderpath, version=args.version)