Skip to content

Commit 003fca4

Browse files
committed
enable pycddlib3
1 parent eade809 commit 003fca4

File tree

5 files changed

+51
-56
lines changed

5 files changed

+51
-56
lines changed

.github/workflows/main.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on: [push, pull_request, workflow_dispatch]
66
jobs:
77
indent:
88
name: indent
9-
runs-on: [ubuntu-20.04]
9+
runs-on: [ubuntu-24.04]
1010

1111
strategy:
1212
matrix:
@@ -34,7 +34,7 @@ jobs:
3434
3535
linux:
3636
name: test
37-
runs-on: [ubuntu-20.04]
37+
runs-on: [ubuntu-24.04]
3838

3939
strategy:
4040
matrix:
@@ -48,14 +48,11 @@ jobs:
4848
python-version: ${{ matrix.python-versions }}
4949
- name: setup
5050
run: |
51-
# pycddlib requires libgmp3-dev
5251
sudo apt update && sudo apt install --yes \
5352
numdiff \
54-
libgmp3-dev \
5553
texlive \
5654
texlive-latex-extra
5755
python -m pip install --upgrade pip
58-
pip install pycddlib==2.1.7 # this is optional
5956
pip install autograd # this is optional
6057
python --version
6158
- name: test

burnman/classes/polytope.py

Lines changed: 34 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,13 @@
1212
from scipy.spatial import Delaunay
1313
from scipy.special import comb
1414
from copy import copy
15+
import cdd
1516

1617
from .material import cached_property
1718

1819
from ..utils.math import independent_row_indices
1920

20-
try:
21-
cdd = importlib.import_module("cdd")
22-
except ImportError as err:
23-
print(
24-
f"Warning: {err}. "
25-
"For full functionality of BurnMan, please install pycddlib."
26-
)
21+
cdd_number_type = "float"
2722

2823

2924
class SimplexGrid(object):
@@ -142,21 +137,21 @@ def __init__(
142137
:param return_fractions: Choose whether the generated polytope object
143138
should return fractions or floats.
144139
:type return_fractions: bool
145-
:param independent_endmember_occupancies: If specified, this array provides
146-
the independent endmember set against which the dependent endmembers
147-
are defined.
140+
:param independent_endmember_occupancies: If specified, this array
141+
provides the independent endmember set against which the
142+
dependent endmembers are defined.
148143
:type independent_endmember_occupancies: numpy.array (2D) or None
149144
"""
150145
self.set_return_type(return_fractions)
151146
self.equality_matrix = equalities[:, 1:]
152147
self.equality_vector = -equalities[:, 0]
153148

154-
self.polytope_matrix = cdd.Matrix(
155-
equalities, linear=True, number_type=number_type
156-
)
149+
self.polytope_matrix = cdd.matrix_from_array(equalities)
150+
self.polytope_matrix.lin_set = set(range(len(equalities)))
157151
self.polytope_matrix.rep_type = cdd.RepType.INEQUALITY
158-
self.polytope_matrix.extend(inequalities, linear=False)
159-
self.polytope = cdd.Polyhedron(self.polytope_matrix)
152+
153+
cdd.matrix_append_to(self.polytope_matrix, cdd.matrix_from_array(inequalities))
154+
self.polytope = cdd.polyhedron_from_matrix(self.polytope_matrix)
160155

161156
if independent_endmember_occupancies is not None:
162157
self.independent_endmember_occupancies = independent_endmember_occupancies
@@ -182,14 +177,14 @@ def raw_vertices(self):
182177
Returns a list of the vertices of the polytope without any
183178
postprocessing. See also endmember_occupancies.
184179
"""
185-
return self.polytope.get_generators()[:]
180+
return cdd.copy_generators(self.polytope).array
186181

187182
@cached_property
188183
def limits(self):
189184
"""
190185
Return the limits of the polytope (the set of bounding inequalities).
191186
"""
192-
return np.array(self.polytope.get_inequalities(), dtype=float)
187+
return np.array(cdd.copy_inequalities(self.polytope).array, dtype=float)
193188

194189
@cached_property
195190
def n_endmembers(self):
@@ -206,7 +201,7 @@ def endmember_occupancies(self):
206201
(a processed list of all of the vertex locations).
207202
"""
208203
if self.return_fractions:
209-
if self.polytope.number_type == "fraction":
204+
if cdd_number_type == "fraction":
210205
v = np.array(
211206
[[Fraction(value) for value in v] for v in self.raw_vertices]
212207
)
@@ -225,7 +220,6 @@ def endmember_occupancies(self):
225220
"The combined equality and positivity "
226221
"constraints result in a null polytope."
227222
)
228-
229223
return v[:, 1:] / v[:, 0, np.newaxis]
230224

231225
@cached_property
@@ -281,37 +275,38 @@ def independent_endmember_polytope(self):
281275
"""
282276
arr = self.endmembers_as_independent_endmember_amounts
283277
arr = np.hstack((np.ones((len(arr), 1)), arr[:, :-1]))
284-
M = cdd.Matrix(arr, number_type="fraction")
278+
M = cdd.matrix_from_array(arr)
285279
M.rep_type = cdd.RepType.GENERATOR
286-
return cdd.Polyhedron(M)
280+
return cdd.polyhedron_from_matrix(M)
287281

288282
@cached_property
289283
def independent_endmember_limits(self):
290284
"""
291285
Gets the limits of the polytope as a function of the independent
292286
endmembers.
293287
"""
294-
return np.array(
295-
self.independent_endmember_polytope.get_inequalities(), dtype=float
296-
)
288+
ind_poly = self.independent_endmember_polytope
289+
inequalities = cdd.copy_inequalities(ind_poly).array
290+
return np.array(inequalities, dtype=float)
297291

298292
def subpolytope_from_independent_endmember_limits(self, limits):
299293
"""
300294
Returns a smaller polytope by applying additional limits to the amounts
301295
of the independent endmembers.
302296
"""
303-
modified_limits = self.independent_endmember_polytope.get_inequalities().copy()
304-
modified_limits.extend(limits, linear=False)
305-
return cdd.Polyhedron(modified_limits)
297+
ind_poly = self.independent_endmember_polytope
298+
modified_limits = cdd.copy_inequalities(ind_poly)
299+
cdd.matrix_append_to(modified_limits, cdd.matrix_from_array(limits))
300+
return cdd.polyhedron_from_matrix(modified_limits)
306301

307302
def subpolytope_from_site_occupancy_limits(self, limits):
308303
"""
309304
Returns a smaller polytope by applying additional limits to the
310305
individual site occupancies.
311306
"""
312-
modified_limits = self.polytope_matrix.copy()
313-
modified_limits.extend(limits, linear=False)
314-
return cdd.Polyhedron(modified_limits)
307+
modified_limits = copy(self.polytope_matrix)
308+
cdd.matrix_append_to(modified_limits, cdd.matrix_from_array(limits))
309+
return cdd.polyhedron_from_matrix(modified_limits)
315310

316311
def grid(
317312
self,
@@ -325,15 +320,16 @@ def grid(
325320
326321
:param points_per_edge: Number of points per edge of the polytope.
327322
:type points_per_edge: int
328-
:param unique_sorted: The gridding is done by splitting the polytope into
329-
a set of simplices. This means that points will be duplicated along
330-
vertices, faces etc. If unique_sorted is True, this function
323+
:param unique_sorted: The gridding is done by splitting the polytope
324+
into a set of simplices. This means that points will be duplicated
325+
along vertices, faces etc. If unique_sorted is True, this function
331326
will sort and make the points unique. This is an expensive
332327
operation for large polytopes, and may not always be necessary.
333328
:type unique_sorted: bool
334329
:param grid_type: Whether to grid the polytope in terms of
335330
independent endmember proportions or site occupancies.
336-
Choices are 'independent endmember proportions' or 'site occupancies'
331+
Choices are 'independent endmember proportions' or
332+
'site occupancies'
337333
:type grid_type: str
338334
:param limits: Additional inequalities restricting the
339335
gridded area of the polytope.
@@ -361,11 +357,8 @@ def grid(
361357
)
362358
else:
363359
if grid_type == "independent endmember proportions":
364-
ppns = np.array(
365-
self.subpolytope_from_independent_endmember_limits(
366-
limits
367-
).get_generators()[:]
368-
)[:, 1:]
360+
plims = self.subpolytope_from_site_occupancy_limits(limits)
361+
ppns = np.array(cdd.copy_generators(plims).array)[:, 1:]
369362
last_ppn = np.array([1.0 - sum(p) for p in ppns]).reshape(
370363
(len(ppns), 1)
371364
)
@@ -377,11 +370,8 @@ def grid(
377370
)
378371

379372
elif grid_type == "site occupancies":
380-
occ = np.array(
381-
self.subpolytope_from_site_occupancy_limits(
382-
limits
383-
).get_generators()[:]
384-
)[:, 1:]
373+
plims = self.subpolytope_from_site_occupancy_limits(limits)
374+
occ = np.array(cdd.copy_generators(plims).array)[:, 1:]
385375
f_occ = occ / (points_per_edge - 1)
386376

387377
ind = self.independent_endmember_occupancies

burnman/tools/chemistry.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,16 +284,23 @@ def reactions_from_stoichiometric_matrix(stoichiometric_matrix):
284284
]
285285
reactions = []
286286
for p in polys:
287-
v = np.array([[value for value in v] for v in p.raw_vertices])
287+
v = np.array(
288+
[
289+
[Rational(value).limit_denominator(1000000) for value in v]
290+
for v in p.raw_vertices
291+
]
292+
)
288293

289294
if v is not []:
290295
reactions.extend(v)
291296

292-
reactions = np.unique(np.array(reactions, dtype=float), axis=0)
293-
294-
reactions = np.array(
295-
[[Rational(value).limit_denominator(1000000) for value in v] for v in reactions]
297+
# There are many duplicate reactions produced by the above procedure
298+
# Here we pick out the unique values
299+
reactions = np.array(reactions)
300+
_, unique_indices = np.unique(
301+
np.array(reactions, dtype=float), return_index=True, axis=0
296302
)
303+
reactions = reactions[unique_indices] # return as rationals
297304

298305
assert np.max(reactions[:-1, 0]) == 0
299306
assert np.max(reactions[-1, 1:]) == 0

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ sympy = "^1.12"
2525
cvxpy = "^1.3"
2626
matplotlib = "^3.7"
2727
numba = "^0.59"
28+
pycddlib-standalone = "^3.0"
2829

2930
[tool.poetry.dev-dependencies]
3031
ipython = "^8.5"

test.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ $PYTHON -m pipdeptree -p burnman -d 1 2> /dev/null
2929
echo ""
3030

3131
# Quietly install optional modules after burnman
32-
echo "Installing optional cvxpy, pycddlib, autograd and jupyter modules ..."
33-
$PYTHON -m pip install -q cvxpy pycddlib==2.1.7 autograd jupyter
32+
echo "Installing optional autograd and jupyter modules ..."
33+
$PYTHON -m pip install -q autograd jupyter
3434
echo ""
3535

3636
function testit {

0 commit comments

Comments
 (0)