Skip to content

Commit 161818c

Browse files
authored
Merge pull request #248 from duartegroup/v1.3.5
V1.3.5
2 parents 6813afd + dded76b commit 161818c

22 files changed

+262
-68
lines changed

.github/pull_request_template.md

+1
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ Please replace _#ISSUE_ with just e.g. #12 if this PR resolves issue 12.
1111
* [ ] The changes include an associated explanation of how/why
1212
* [ ] Test pass
1313
* [ ] Documentation has been updated
14+
* [ ] Changelog has been updated

.github/workflows/catch.yml

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
branches:
66
- master
77
pull_request:
8+
paths-ignore:
9+
- 'doc/**'
10+
- 'examples/**'
811

912
env:
1013
BUILD_TYPE: Release

.github/workflows/pytest.yml

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ on:
55
branches:
66
- master
77
pull_request:
8+
paths-ignore:
9+
- 'doc/**'
10+
- 'examples/**'
811

912
concurrency:
1013
group: ${{ github.workflow }}-${{ github.ref }}

.github/workflows/pytest_cov.yml

+4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ on:
44
push:
55
branches:
66
- master
7+
- 'v[0-9]+.[0-9]+.[0-9]+'
78
pull_request:
9+
paths-ignore:
10+
- 'doc/**'
11+
- 'examples/**'
812

913
concurrency:
1014
group: ${{ github.workflow }}-${{ github.ref }}

autode/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
- Merge when tests pass
4040
"""
4141

42-
__version__ = "1.3.4"
42+
__version__ = "1.3.5"
4343

4444

4545
__all__ = [

autode/hessians.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ def _mass_weighted(self) -> np.ndarray:
234234
axis=np.newaxis,
235235
)
236236

237-
return Hessian(
238-
H / np.sqrt(np.outer(mass_array, mass_array)), units="J m^-2 kg^-1"
239-
)
237+
return np.array(
238+
H / np.sqrt(np.outer(mass_array, mass_array))
239+
) # J Å^-2 kg^-1
240240

241241
@cached_property
242242
def _proj_mass_weighted(self) -> np.ndarray:

autode/log/log.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
"""
55
Set up logging with the standard python logging module. Set the log level with
6-
$AUTODE_LOG_LEVEL = {'', INFO, WARNING, DEBUG}
6+
$AUTODE_LOG_LEVEL = {'', ERROR, WARNING, INFO, DEBUG}
77
88
i.e. export AUTODE_LOG_LEVEL=DEBUG
99
@@ -36,6 +36,9 @@ def get_log_level():
3636
if log_level_str == "INFO":
3737
return logging.INFO
3838

39+
if log_level_str == "ERROR":
40+
return logging.ERROR
41+
3942
return logging.CRITICAL
4043

4144

autode/units.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -211,15 +211,15 @@ def energy_unit_from_name(name: str) -> "autode.units.Unit":
211211

212212

213213
ha_per_ang = CompositeUnit(
214-
ha, per=[ang], aliases=["ha Å-1", "ha Å^-1", "ha/ang"]
214+
ha, per=[ang], aliases=["ha / Å", "ha Å-1", "ha Å^-1", "ha/ang"]
215215
)
216216

217217
ha_per_a0 = CompositeUnit(
218-
ha, per=[a0], aliases=["ha a0-1", "ha a0^-1", "ha/bohr"]
218+
ha, per=[a0], aliases=["ha / a0", "ha a0-1", "ha a0^-1", "ha/bohr"]
219219
)
220220

221221
ev_per_ang = CompositeUnit(
222-
ev, per=[ang], aliases=["ha a0-1", "ev Å^-1", "ev/ang"]
222+
ev, per=[ang], aliases=["ev / Å", "ev Å^-1", "ev/ang"]
223223
)
224224

225225
kcalmol_per_ang = CompositeUnit(

autode/values.py

+60-32
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@
3737
)
3838

3939

40-
def _to(value: Union["Value", "ValueArray"], units: Union[Unit, str]):
40+
def _to(
41+
value: Union["Value", "ValueArray"], units: Union[Unit, str], inplace: bool
42+
) -> Any:
4143
"""
42-
Convert a value or value array to a new unit and return a copy
44+
Convert a value or value array to a new unit and return a copy if
45+
inplace=False
4346
4447
---------------------------------------------------------------------------
4548
Arguments:
@@ -62,26 +65,29 @@ def _to(value: Union["Value", "ValueArray"], units: Union[Unit, str]):
6265

6366
except StopIteration:
6467
raise TypeError(
65-
f"No viable unit conversion from {value.units} " f"-> {units}"
68+
f"No viable unit conversion from {value.units} -> {units}"
6669
)
6770

68-
# Convert to the base unit, then to the new units
69-
c = float(units.conversion / value.units.conversion)
70-
71-
if isinstance(value, Value):
72-
return value.__class__(float(value) * c, units=units)
73-
74-
elif isinstance(value, ValueArray):
75-
value[:] = np.array(value, copy=True) * c
76-
value.units = units
77-
return value
78-
79-
else:
71+
if not (isinstance(value, Value) or isinstance(value, ValueArray)):
8072
raise ValueError(
8173
f"Cannot convert {value} to new units. Must be one of"
8274
f" Value of ValueArray"
8375
)
8476

77+
if isinstance(value, Value) and inplace:
78+
raise ValueError(
79+
"Cannot modify a value inplace as floats are immutable"
80+
)
81+
82+
# Convert to the base unit, then to the new units
83+
c = float(units.conversion / value.units.conversion)
84+
85+
new_value = value if inplace else value.copy()
86+
new_value *= c
87+
new_value.units = units
88+
89+
return None if inplace else new_value
90+
8591

8692
def _units_init(value, units: Union[Unit, str, None]):
8793
"""Initialise the units of this value
@@ -171,6 +177,11 @@ def _other_same_units(self, other):
171177

172178
return other.to(self.units)
173179

180+
def _like_self_from_float(self, value: float) -> "Value":
181+
new_value = self.__class__(value, units=self.units)
182+
new_value.__dict__.update(self.__dict__)
183+
return new_value
184+
174185
def __eq__(self, other) -> bool:
175186
"""Equality of two values, which may be in different units"""
176187

@@ -210,20 +221,26 @@ def __add__(self, other) -> "Value":
210221
if isinstance(other, np.ndarray):
211222
return other + float(self)
212223

213-
return self.__class__(
214-
float(self) + self._other_same_units(other), units=self.units
224+
return self._like_self_from_float(
225+
float(self) + self._other_same_units(other)
215226
)
216227

217-
def __mul__(self, other) -> "Value":
228+
def __mul__(self, other) -> Union[float, "Value"]:
218229
"""Multiply this value with another"""
219230
if isinstance(other, np.ndarray):
220231
return other * float(self)
221232

222-
return self.__class__(
223-
float(self) * self._other_same_units(other), units=self.units
233+
if isinstance(other, Value):
234+
logger.warning(
235+
"Multiplying autode.Value returns a float with no units"
236+
)
237+
return float(self) * self._other_same_units(other)
238+
239+
return self._like_self_from_float(
240+
float(self) * self._other_same_units(other)
224241
)
225242

226-
def __rmul__(self, other) -> "Value":
243+
def __rmul__(self, other) -> Union[float, "Value"]:
227244
return self.__mul__(other)
228245

229246
def __radd__(self, other) -> "Value":
@@ -232,16 +249,13 @@ def __radd__(self, other) -> "Value":
232249
def __sub__(self, other) -> "Value":
233250
return self.__add__(-other)
234251

235-
def __floordiv__(self, other):
236-
raise NotImplementedError(
237-
"Integer division is not supported by " "autode.values.Value"
238-
)
252+
def __floordiv__(self, other) -> Union[float, "Value"]:
253+
x = float(self) // self._other_same_units(other)
254+
return x if isinstance(other, Value) else self._like_self_from_float(x)
239255

240-
def __truediv__(self, other) -> "Value":
241-
return self.__class__(
242-
float(self) / float(self._other_same_units(other)),
243-
units=self.units,
244-
)
256+
def __truediv__(self, other) -> Union[float, "Value"]:
257+
x = float(self) / self._other_same_units(other)
258+
return x if isinstance(other, Value) else self._like_self_from_float(x)
245259

246260
def __abs__(self) -> "Value":
247261
"""Absolute value"""
@@ -260,7 +274,7 @@ def to(self, units):
260274
Raises:
261275
(TypeError):
262276
"""
263-
return _to(self, units)
277+
return _to(self, units, inplace=False)
264278

265279

266280
class Energy(Value):
@@ -643,7 +657,21 @@ def to(self, units) -> Any:
643657
Raises:
644658
(TypeError):
645659
"""
646-
return _to(self, units)
660+
return _to(self, units, inplace=False)
661+
662+
def to_(self, units) -> None:
663+
"""
664+
Convert this array into a set of new units, inplace. This will not copy
665+
the array
666+
667+
-----------------------------------------------------------------------
668+
Returns:
669+
(None)
670+
671+
Raises:
672+
(TypeError):
673+
"""
674+
_to(self, units, inplace=True)
647675

648676
def __array_finalize__(self, obj):
649677
"""See https://numpy.org/doc/stable/user/basics.subclassing.html"""

autode/wrappers/QChem.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -158,17 +158,24 @@ def coordinates_from(self, calc: "CalculationExecutor") -> Coordinates:
158158
"Non-optimisation calculation performed - no change"
159159
" to geometry"
160160
)
161-
return calc.molecule.atoms
161+
return calc.molecule.coordinates
162+
163+
if calc.molecule.n_atoms == 1:
164+
# Coordinate of a single atom will not change
165+
return calc.molecule.coordinates
162166

163167
coords = []
164168

165169
for i, line in enumerate(calc.output.file_lines):
166170

167-
if "Coordinates (Angstroms)" not in line:
171+
if "Coordinates (Angstroms)" in line:
172+
start_idx = i + 2
173+
elif "Standard Nuclear Orientation (Angstroms)" in line:
174+
start_idx = i + 3
175+
else:
168176
continue
169177

170-
"""e.g.
171-
178+
"""e.g.
172179
Coordinates (Angstroms)
173180
ATOM X Y Z
174181
1 O 0.0003489977 -0.1403224128 0.0000000000
@@ -177,7 +184,6 @@ def coordinates_from(self, calc: "CalculationExecutor") -> Coordinates:
177184
Point Group: cs Number of degrees of freedom: 3
178185
"""
179186

180-
start_idx = i + 2
181187
end_idx = start_idx + calc.molecule.n_atoms
182188
coords = []
183189
for cline in calc.output.file_lines[start_idx:end_idx]:

autode/wrappers/XTB.py

+18-16
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,31 @@ def print_cartesian_constraints(self, inp_file, molecule):
5050
if molecule.constraints.cartesian is None:
5151
return None
5252

53-
constrained_atom_idxs = [i + 1 for i in molecule.constraints.cartesian]
54-
list_of_ranges, used_atoms = [], []
55-
56-
for i in constrained_atom_idxs:
57-
atom_range = []
58-
if i not in used_atoms:
59-
while i in constrained_atom_idxs:
60-
used_atoms.append(i)
61-
atom_range.append(i)
62-
i += 1
63-
if len(atom_range) in (1, 2):
64-
list_of_ranges += str(atom_range)
65-
else:
66-
list_of_ranges.append(f"{atom_range[0]}-{atom_range[-1]}")
53+
atom_idxs = list(
54+
sorted(int(i) + 1 for i in molecule.constraints.cartesian)
55+
)
56+
list_of_ranges = []
6757

58+
for atom_idx in atom_idxs:
59+
last_range = (
60+
list_of_ranges[-1] if len(list_of_ranges) > 0 else None
61+
)
62+
if last_range is not None and atom_idx - 1 == last_range[-1]:
63+
last_range.append(atom_idx)
64+
else:
65+
list_of_ranges.append([atom_idx])
66+
67+
list_of_ranges_str = [
68+
f"{idxs[0]}-{idxs[-1]}" if len(idxs) > 1 else str(idxs[0])
69+
for idxs in list_of_ranges
70+
]
6871
print(
6972
f"$constrain\n"
7073
f"force constant={self.force_constant}\n"
71-
f'atoms: {",".join(list_of_ranges)}\n'
74+
f'atoms: {",".join(list_of_ranges_str)}\n'
7275
f"$",
7376
file=inp_file,
7477
)
75-
7678
return None
7779

7880
@staticmethod

doc/changelog.rst

+25-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,30 @@
11
Changelog
22
=========
33

4+
1.3.5
5+
--------
6+
----------
7+
8+
9+
Usability improvements/Changes
10+
******************************
11+
- :code:`autode.value.ValueArray.to()` now defaults to copying the object rather than inplace modification
12+
13+
14+
Functionality improvements
15+
**************************
16+
- Adds a :code:`to_` method to :code:`autode.value.ValueArray` for explicit inplace modification of the array
17+
18+
19+
Bug Fixes
20+
*********
21+
- Fixes :code:`ERROR` logging level being ignored from environment variable :code:`AUTODE_LOG_LEVEL`
22+
- Fixes :code:`autode.values.Value` instances generating items with units on division, and throw a warning if multiplying
23+
- Fixes the printing of cartesian constraints in XTB input files, meaning they are no longer ignored
24+
- Fixes :code:`Hessian` instances changing units when normal modes are calculated
25+
- Fixes an incorrect alias for :code:`ev_per_ang`
26+
27+
428
1.3.4
529
--------
630
----------
@@ -10,7 +34,6 @@ Feature additions.
1034
Usability improvements/Changes
1135
******************************
1236
* Throw useful exception for invalid :code:`ade.Config.ts_template_folder_path`
13-
* Adds the reaction temperature to the unique reaction hash
1437

1538

1639
Functionality improvements
@@ -22,7 +45,7 @@ Functionality improvements
2245

2346
Bug Fixes
2447
*********
25-
-
48+
- Fixes calculation :code:`clean_up()` failing with a null filename
2649

2750

2851
1.3.3

doc/config.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ to see all the options.
136136
Logging
137137
-------
138138

139-
To set the logging level to one of {INFO, WARNING, ERROR} set the :code:`AUTODE_LOG_LEVEL`
139+
To set the logging level to one of {DEBUG, INFO, WARNING, ERROR} set the :code:`AUTODE_LOG_LEVEL`
140140
environment variable, in bash::
141141

142142
$ export AUTODE_LOG_LEVEL=INFO

0 commit comments

Comments
 (0)