From 8398f24e7041a10b3d985e037e3967ab9a79ff0e Mon Sep 17 00:00:00 2001 From: Andreas Stamminger Date: Mon, 14 Jan 2019 11:04:15 +0100 Subject: [PATCH] Introduce more intuitive method names in Data classes and reduce required input parameter for TrajectoryData.set_trajectory() method (#2310) * Rename ArrayData.iterarrays() to ArrayData.get_iterarrays() * [TrajectoryData] Rename _get_aiida_structure() -> get_structure() * [TrajectoryData] Rename _get_cif() -> get_cif() * Rename _get_cif() -> get_cit() in tcod.py * [StructureData] Rename _get_cif() -> get_cif() * Make stepid and cells parameter optional Change TrajectoryData to make passing stepids and cells optional. While nothing will be stored for cells if not given a consecutive sequence will be automatically assigned to stepids if missing from the inputs. * Store symbols in TrajectoryData attribute instead of array As proposed in issue #201 symbols are now stored in a TrajectoryData attribute rather than an array to simplify the query for these symbols * Change passed symbols from numpy.ndarray to list in set_structurelist * Change TrajectoryData tests to use symbols attribute rather than symbols array * Make Code.is_hidden() available as class property * Rename Code.full_text_info() method to .get_full_text_info() * Change RemoteData.is_empty() method to class property .is_empty * Change is_alloy() and has_vacancies() methods to properties Make class methods .is_alloy() and .has_vacancies() for StrutureData and Kind classes accessible as class properties .is_alloy and .has_vacancies * Change symbols type from numpy.array to list * Add deprecation warning to renamed methods * Rename code attribute is_hidden to hidden. * Set allowed symbols type to be Iterable rather than list * Ensure symbols are stored as list * Adjust argument ordering in set_trajectory() docstring. * Document introduced changes in concepts/workflows --- .../tests/cmdline/commands/test_code.py | 4 +- .../tests/cmdline/commands/test_data.py | 2 +- .../tests/cmdline/commands/test_node.py | 2 +- aiida/backends/tests/dataclasses.py | 118 ++++++------ aiida/backends/tests/orm/data/remote.py | 4 +- aiida/backends/tests/tcodexporter.py | 4 +- aiida/cmdline/commands/cmd_code.py | 2 +- aiida/orm/data/array/__init__.py | 14 ++ aiida/orm/data/array/trajectory.py | 181 ++++++++++++------ aiida/orm/data/cif.py | 26 ++- aiida/orm/data/code.py | 12 +- aiida/orm/data/remote.py | 1 + aiida/orm/data/structure.py | 35 +++- aiida/tools/dbexporters/tcod.py | 6 +- aiida/tools/dbimporters/baseclasses.py | 2 +- docs/source/concepts/workflows.rst | 12 ++ 16 files changed, 286 insertions(+), 139 deletions(-) diff --git a/aiida/backends/tests/cmdline/commands/test_code.py b/aiida/backends/tests/cmdline/commands/test_code.py index cb62b5b508..b5471b9d27 100644 --- a/aiida/backends/tests/cmdline/commands/test_code.py +++ b/aiida/backends/tests/cmdline/commands/test_code.py @@ -146,13 +146,13 @@ def test_hide_one(self): result = self.cli_runner.invoke(hide, [str(self.code.pk)]) self.assertIsNone(result.exception, result.output) - self.assertTrue(self.code.is_hidden()) + self.assertTrue(self.code.hidden) def test_reveal_one(self): result = self.cli_runner.invoke(reveal, [str(self.code.pk)]) self.assertIsNone(result.exception, result.output) - self.assertFalse(self.code.is_hidden()) + self.assertFalse(self.code.hidden) def test_relabel_code(self): result = self.cli_runner.invoke(relabel, [str(self.code.pk), 'new_code']) diff --git a/aiida/backends/tests/cmdline/commands/test_data.py b/aiida/backends/tests/cmdline/commands/test_data.py index eb762c8ec2..4ebe5e8f23 100644 --- a/aiida/backends/tests/cmdline/commands/test_data.py +++ b/aiida/backends/tests/cmdline/commands/test_data.py @@ -518,7 +518,7 @@ def create_trajectory_data(): 0., 3., ]]]) - symbols = numpy.array(['H', 'O', 'C']) + symbols = ['H', 'O', 'C'] positions = numpy.array([[[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]], [[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]]) velocities = numpy.array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], diff --git a/aiida/backends/tests/cmdline/commands/test_node.py b/aiida/backends/tests/cmdline/commands/test_node.py index c98e7a18f1..22327d895e 100644 --- a/aiida/backends/tests/cmdline/commands/test_node.py +++ b/aiida/backends/tests/cmdline/commands/test_node.py @@ -518,7 +518,7 @@ def create_trajectory_data(): 0., 3., ]]]) - symbols = numpy.array(['H', 'O', 'C']) + symbols = ['H', 'O', 'C'] positions = numpy.array([[[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]], [[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]]) velocities = numpy.array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], diff --git a/aiida/backends/tests/dataclasses.py b/aiida/backends/tests/dataclasses.py index f6de508707..f26a810c2f 100644 --- a/aiida/backends/tests/dataclasses.py +++ b/aiida/backends/tests/dataclasses.py @@ -256,7 +256,7 @@ def test_change_cifdata_file(self): @unittest.skipIf(not has_ase(), "Unable to import ase") @unittest.skipIf(not has_pycifrw(), "Unable to import PyCifRW") - def test_get_aiida_structure(self): + def test_get_structure(self): import tempfile from aiida.orm.data.cif import CifData @@ -286,9 +286,9 @@ def test_get_aiida_structure(self): a = CifData(file=tmpf.name) with self.assertRaises(ValueError): - a._get_aiida_structure(converter='none') + a.get_structure(converter='none') - c = a._get_aiida_structure() + c = a.get_structure() self.assertEquals(c.get_kind_names(), ['C', 'O']) @@ -330,13 +330,13 @@ def test_ase_primitive_and_conventional_cells_ase(self): tmpf.flush() c = CifData(file=tmpf.name) - ase = c._get_aiida_structure(converter='ase', primitive_cell=False).get_ase() + ase = c.get_structure(converter='ase', primitive_cell=False).get_ase() self.assertEquals(ase.get_number_of_atoms(), 15) - ase = c._get_aiida_structure(converter='ase').get_ase() + ase = c.get_structure(converter='ase').get_ase() self.assertEquals(ase.get_number_of_atoms(), 15) - ase = c._get_aiida_structure(converter='ase', primitive_cell=True, subtrans_included=False).get_ase() + ase = c.get_structure(converter='ase', primitive_cell=True, subtrans_included=False).get_ase() self.assertEquals(ase.get_number_of_atoms(), 5) @unittest.skipIf(not has_ase(), "Unable to import ase") @@ -389,13 +389,13 @@ def test_ase_primitive_and_conventional_cells_pymatgen(self): tmpf.flush() c = CifData(file=tmpf.name) - ase = c._get_aiida_structure(converter='pymatgen', primitive_cell=False).get_ase() + ase = c.get_structure(converter='pymatgen', primitive_cell=False).get_ase() self.assertEquals(ase.get_number_of_atoms(), 15) - ase = c._get_aiida_structure(converter='pymatgen').get_ase() + ase = c.get_structure(converter='pymatgen').get_ase() self.assertEquals(ase.get_number_of_atoms(), 15) - ase = c._get_aiida_structure(converter='pymatgen', primitive_cell=True).get_ase() + ase = c.get_structure(converter='pymatgen', primitive_cell=True).get_ase() self.assertEquals(ase.get_number_of_atoms(), 5) @unittest.skipIf(not has_pycifrw(), "Unable to import PyCifRW") @@ -917,8 +917,8 @@ def test_sum_one_general(self): from aiida.orm.data.structure import Kind a = Kind(symbols=['Ba', 'C'], weights=[1. / 3., 2. / 3.]) - self.assertTrue(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertFalse(a.has_vacancies) def test_sum_less_one_general(self): """ @@ -927,8 +927,8 @@ def test_sum_less_one_general(self): from aiida.orm.data.structure import Kind a = Kind(symbols=['Ba', 'C'], weights=[1. / 3., 1. / 3.]) - self.assertTrue(a.is_alloy()) - self.assertTrue(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertTrue(a.has_vacancies) def test_no_position(self): """ @@ -946,16 +946,16 @@ def test_simple(self): from aiida.orm.data.structure import Kind a = Kind(symbols='Ba') - self.assertFalse(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertFalse(a.is_alloy) + self.assertFalse(a.has_vacancies) b = Kind(symbols='Ba', weights=1.) - self.assertFalse(b.is_alloy()) - self.assertFalse(b.has_vacancies()) + self.assertFalse(b.is_alloy) + self.assertFalse(b.has_vacancies) c = Kind(symbols='Ba', weights=None) - self.assertFalse(c.is_alloy()) - self.assertFalse(c.has_vacancies()) + self.assertFalse(c.is_alloy) + self.assertFalse(c.has_vacancies) def test_automatic_name(self): """ @@ -1181,24 +1181,24 @@ def test_cell_ok_and_atoms(self): a.append_atom(position=(0., 0., 0.), symbols=['Ba']) a.append_atom(position=(1., 1., 1.), symbols=['Ti']) a.append_atom(position=(1.2, 1.4, 1.6), symbols=['Ti']) - self.assertFalse(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertFalse(a.is_alloy) + self.assertFalse(a.has_vacancies) # There should be only two kinds! (two atoms of kind Ti should # belong to the same kind) self.assertEquals(len(a.kinds), 2) a.append_atom(position=(0.5, 1., 1.5), symbols=['O', 'C'], weights=[0.5, 0.5]) - self.assertTrue(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertFalse(a.has_vacancies) a.append_atom(position=(0.5, 1., 1.5), symbols=['O'], weights=[0.5]) - self.assertTrue(a.is_alloy()) - self.assertTrue(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertTrue(a.has_vacancies) a.clear_kinds() a.append_atom(position=(0.5, 1., 1.5), symbols=['O'], weights=[0.5]) - self.assertFalse(a.is_alloy()) - self.assertTrue(a.has_vacancies()) + self.assertFalse(a.is_alloy) + self.assertTrue(a.has_vacancies) def test_cell_ok_and_unknown_atoms(self): """ @@ -1216,24 +1216,24 @@ def test_cell_ok_and_unknown_atoms(self): a.append_atom(position=(0., 0., 0.), symbols=['Ba']) a.append_atom(position=(1., 1., 1.), symbols=['X']) a.append_atom(position=(1.2, 1.4, 1.6), symbols=['X']) - self.assertFalse(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertFalse(a.is_alloy) + self.assertFalse(a.has_vacancies) # There should be only two kinds! (two atoms of kind X should # belong to the same kind) self.assertEquals(len(a.kinds), 2) a.append_atom(position=(0.5, 1., 1.5), symbols=['O', 'C'], weights=[0.5, 0.5]) - self.assertTrue(a.is_alloy()) - self.assertFalse(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertFalse(a.has_vacancies) a.append_atom(position=(0.5, 1., 1.5), symbols=['O'], weights=[0.5]) - self.assertTrue(a.is_alloy()) - self.assertTrue(a.has_vacancies()) + self.assertTrue(a.is_alloy) + self.assertTrue(a.has_vacancies) a.clear_kinds() a.append_atom(position=(0.5, 1., 1.5), symbols=['X'], weights=[0.5]) - self.assertFalse(a.is_alloy()) - self.assertTrue(a.has_vacancies()) + self.assertFalse(a.is_alloy) + self.assertTrue(a.has_vacancies) def test_kind_1(self): """ @@ -1827,7 +1827,7 @@ def test_get_cif(self): a.append_atom(position=(0.5, 0.5, 0.5), symbols=['Ba']) a.append_atom(position=(1., 1., 1.), symbols=['Ti']) - c = a._get_cif() + c = a.get_cif() lines = c._prepare_cif()[0].decode('utf-8').split('\n') non_comments = [] for line in lines: @@ -1971,8 +1971,8 @@ def test_lock(self): a.pbc = [True, True, True] _ = a.get_cell_volume() - _ = a.is_alloy() - _ = a.has_vacancies() + _ = a.is_alloy + _ = a.has_vacancies b = a.clone() # I check that clone returned an unstored copy and so can be altered @@ -2819,7 +2819,7 @@ def test_creation(self): def test_iteration(self): """ - Check the functionality of the iterarrays() iterator + Check the functionality of the get_iterarrays() iterator """ from aiida.orm.data.array import ArrayData import numpy @@ -2835,7 +2835,7 @@ def test_iteration(self): third = numpy.random.rand(6, 6) n.set_array('third', third) - for name, array in n.iterarrays(): + for name, array in n.get_iterarrays(): if name == 'first': self.assertAlmostEquals(abs(first - array).max(), 0.) if name == 'second': @@ -2887,7 +2887,7 @@ def test_creation(self): 0., 3., ]]]) - symbols = numpy.array(['H', 'O', 'C']) + symbols = ['H', 'O', 'C'] positions = numpy.array([[[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]], [[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]]) velocities = numpy.array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], @@ -2903,7 +2903,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertAlmostEqual(abs(times - n.get_times()).sum(), 0.) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertAlmostEqual(abs(velocities - n.get_velocities()).sum(), 0.) @@ -2912,7 +2912,7 @@ def test_creation(self): self.assertEqual(data[0], stepids[1]) self.assertAlmostEqual(data[1], times[1]) self.assertAlmostEqual(abs(cells[1] - data[2]).sum(), 0.) - self.assertEqual(symbols.tolist(), data[3].tolist()) + self.assertEqual(symbols, data[3]) self.assertAlmostEqual(abs(data[4] - positions[1]).sum(), 0.) self.assertAlmostEqual(abs(data[5] - velocities[1]).sum(), 0.) @@ -2931,7 +2931,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertIsNone(n.get_times()) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -2944,7 +2944,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertIsNone(n.get_times()) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -2957,7 +2957,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertAlmostEqual(abs(times - n.get_times()).sum(), 0.) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -2970,7 +2970,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertAlmostEqual(abs(times - n.get_times()).sum(), 0.) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -2983,7 +2983,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertAlmostEqual(abs(times - n.get_times()).sum(), 0.) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -2992,7 +2992,7 @@ def test_creation(self): self.assertEqual(data[0], stepids[1]) self.assertAlmostEqual(data[1], times[1]) self.assertAlmostEqual(abs(cells[1] - data[2]).sum(), 0.) - self.assertEqual(symbols.tolist(), data[3].tolist()) + self.assertEqual(symbols, data[3]) self.assertAlmostEqual(abs(data[4] - positions[1]).sum(), 0.) self.assertIsNone(data[5]) @@ -3011,7 +3011,7 @@ def test_creation(self): self.assertAlmostEqual(abs(stepids - n.get_stepids()).sum(), 0.) self.assertAlmostEqual(abs(times - n.get_times()).sum(), 0.) self.assertAlmostEqual(abs(cells - n.get_cells()).sum(), 0.) - self.assertEqual(symbols.tolist(), n.get_symbols().tolist()) + self.assertEqual(symbols, n.symbols) self.assertAlmostEqual(abs(positions - n.get_positions()).sum(), 0.) self.assertIsNone(n.get_velocities()) @@ -3020,7 +3020,7 @@ def test_creation(self): self.assertEqual(data[0], stepids[1]) self.assertAlmostEqual(data[1], times[1]) self.assertAlmostEqual(abs(cells[1] - data[2]).sum(), 0.) - self.assertEqual(symbols.tolist(), data[3].tolist()) + self.assertEqual(symbols, data[3]) self.assertAlmostEqual(abs(data[4] - positions[1]).sum(), 0.) self.assertIsNone(data[5]) @@ -3069,7 +3069,7 @@ def test_conversion_to_structure(self): 0., 3., ]]]) - symbols = numpy.array(['H', 'O', 'C']) + symbols = ['H', 'O', 'C'] positions = numpy.array([[[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]], [[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]]) velocities = numpy.array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], @@ -3080,15 +3080,15 @@ def test_conversion_to_structure(self): stepids=stepids, cells=cells, symbols=symbols, positions=positions, times=times, velocities=velocities) from_step = n.get_step_structure(1) - from_get_aiida_structure = n._get_aiida_structure(index=1) + from_get_structure = n.get_structure(index=1) - for struc in [from_step, from_get_aiida_structure]: + for struc in [from_step, from_get_structure]: self.assertEqual(len(struc.sites), 3) # 3 sites self.assertAlmostEqual(abs(numpy.array(struc.cell) - cells[1]).sum(), 0) newpos = numpy.array([s.position for s in struc.sites]) self.assertAlmostEqual(abs(newpos - positions[1]).sum(), 0) newkinds = [s.kind_name for s in struc.sites] - self.assertEqual(newkinds, symbols.tolist()) + self.assertEqual(newkinds, symbols) # Weird assignments (nobody should ever do this, but it is possible in # principle and we want to check @@ -3123,7 +3123,7 @@ def test_conversion_to_structure(self): self.assertAlmostEqual(abs(newpos - positions[1]).sum(), 0) newkinds = [s.kind_name for s in struc.sites] # Kinds are in the same order as given in the custm_kinds list - self.assertEqual(newkinds, symbols.tolist()) + self.assertEqual(newkinds, symbols) newatomtypes = [struc.get_kind(s.kind_name).symbols[0] for s in struc.sites] # Atoms remain in the same order as given in the positions list self.assertEqual(newatomtypes, ['He', 'Os', 'Cu']) @@ -3175,7 +3175,7 @@ def test_conversion_from_structurelist(self): td = TrajectoryData(structurelist=structurelist) self.assertEqual(td.get_cells().tolist(), cells) - self.assertEqual(td.get_symbols().tolist(), symbols[0]) + self.assertEqual(td.symbols, symbols[0]) self.assertEqual(td.get_positions().tolist(), positions) symbols = [['H', 'O', 'C'], ['H', 'O', 'P']] @@ -3229,7 +3229,7 @@ def test_export_to_file(self): 0., 3., ]]]) - symbols = numpy.array(['H', 'O', 'C']) + symbols = ['H', 'O', 'C'] positions = numpy.array([[[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]], [[0., 0., 0.], [0.5, 0.5, 0.5], [1.5, 1.5, 1.5]]]) velocities = numpy.array([[[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]], [[0.5, 0.5, 0.5], [0.5, 0.5, 0.5], @@ -3274,7 +3274,7 @@ def test_export_to_file(self): class TestKpointsData(AiidaTestCase): """ - Tests the TrajectoryData objects. + Tests the KpointsData objects. """ def test_set_kpoints_path_legacy(self): diff --git a/aiida/backends/tests/orm/data/remote.py b/aiida/backends/tests/orm/data/remote.py index f6bb461268..366f354dad 100644 --- a/aiida/backends/tests/orm/data/remote.py +++ b/aiida/backends/tests/orm/data/remote.py @@ -58,6 +58,6 @@ def tearDown(self): def test_clean(self): """Try cleaning a RemoteData node.""" - self.assertFalse(self.remote.is_empty()) + self.assertFalse(self.remote.is_empty) self.remote._clean() - self.assertTrue(self.remote.is_empty()) + self.assertTrue(self.remote.is_empty) diff --git a/aiida/backends/tests/tcodexporter.py b/aiida/backends/tests/tcodexporter.py index 5a48ea236e..8857bc767b 100644 --- a/aiida/backends/tests/tcodexporter.py +++ b/aiida/backends/tests/tcodexporter.py @@ -157,7 +157,7 @@ def test_cif_structure_roundtrip(self): tmpf.flush() a = CifData(file=tmpf.name) - c = a._get_aiida_structure() + c = a.get_structure() c.store() pd = ParameterData() @@ -253,7 +253,7 @@ def test_inline_export(self): tmpf.flush() a = CifData(file=tmpf.name) - s = a._get_aiida_structure(store=True) + s = a.get_structure(store=True) val = export_values(s) script = val.first_block()['_tcod_file_contents'][1] function = '_get_aiida_structure_pymatgen_inline' diff --git a/aiida/cmdline/commands/cmd_code.py b/aiida/cmdline/commands/cmd_code.py index 986c22668a..5e53cdf0b6 100644 --- a/aiida/cmdline/commands/cmd_code.py +++ b/aiida/cmdline/commands/cmd_code.py @@ -166,7 +166,7 @@ def code_duplicate(ctx, code, non_interactive, **kwargs): @with_dbenv() def show(code, verbose): """Display detailed information for the given CODE.""" - click.echo(tabulate.tabulate(code.full_text_info(verbose))) + click.echo(tabulate.tabulate(code.get_full_text_info(verbose))) @verdi_code.command() diff --git a/aiida/orm/data/array/__init__.py b/aiida/orm/data/array/__init__.py index c403f3eba7..0d71269d90 100644 --- a/aiida/orm/data/array/__init__.py +++ b/aiida/orm/data/array/__init__.py @@ -95,6 +95,20 @@ def iterarrays(self): Iterator that returns tuples (name, array) for each array stored in the node. """ + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn( # pylint: disable=no-member + 'This method has been deprecated and will be renamed to get_iterarrays() in AiiDA v1.0', DeprecationWarning) + return self.get_iterarrays() + + def get_iterarrays(self): + """ + Iterator that returns tuples (name, array) for each array stored in the + node. + + .. versionadded:: 1.0 + Renamed from iterarrays + """ for name in self.get_arraynames(): yield (name, self.get_array(name)) diff --git a/aiida/orm/data/array/trajectory.py b/aiida/orm/data/array/trajectory.py index 1b4b0d62db..004e998a65 100644 --- a/aiida/orm/data/array/trajectory.py +++ b/aiida/orm/data/array/trajectory.py @@ -14,6 +14,7 @@ from __future__ import absolute_import from __future__ import print_function +import collections import six from six.moves import range, zip @@ -50,31 +51,34 @@ def _internal_validate(self, stepids, cells, symbols, positions, times, velociti """ import numpy - if not isinstance(stepids, numpy.ndarray) or stepids.dtype != int: - raise TypeError("TrajectoryData.stepids must be a numpy array of integers") - if not isinstance(cells, numpy.ndarray) or cells.dtype != float: - raise TypeError("TrajectoryData.cells must be a numpy array of floats") - if not isinstance(symbols, numpy.ndarray): - raise TypeError("TrajectoryData.symbols must be a numpy array") + if not isinstance(symbols, collections.Iterable): + raise TypeError("TrajectoryData.symbols must be of type list") if any([not isinstance(i, six.string_types) for i in symbols]): - raise TypeError("TrajectoryData.symbols must be a numpy array of strings") + raise TypeError("TrajectoryData.symbols must be a 1d list of strings") if not isinstance(positions, numpy.ndarray) or positions.dtype != float: raise TypeError("TrajectoryData.positions must be a numpy array of floats") + if stepids is not None: + if not isinstance(stepids, numpy.ndarray) or stepids.dtype != int: + raise TypeError("TrajectoryData.stepids must be a numpy array of integers") + if cells is not None: + if not isinstance(cells, numpy.ndarray) or cells.dtype != float: + raise TypeError("TrajectoryData.cells must be a numpy array of floats") if times is not None: if not isinstance(times, numpy.ndarray) or times.dtype != float: raise TypeError("TrajectoryData.times must be a numpy array of floats") if velocities is not None: if not isinstance(velocities, numpy.ndarray) or velocities.dtype != float: raise TypeError("TrajectoryData.velocities must be a numpy array of floats, or None") - - numsteps = stepids.size - if stepids.shape != (numsteps,): - raise ValueError("TrajectoryData.stepids must be a 1d array") - if cells.shape != (numsteps, 3, 3): - raise ValueError("TrajectoryData.cells must have shape (s,3,3), with s=number of steps") - numatoms = symbols.size - if symbols.shape != (numatoms,): - raise ValueError("TrajectoryData.symbols must be a 1d array") + if stepids is not None: + numsteps = stepids.size + if stepids.shape != (numsteps,): + raise ValueError("TrajectoryData.stepids must be a 1d array") + else: + numsteps = positions.shape[0] + if cells is not None: + if cells.shape != (numsteps, 3, 3): + raise ValueError("TrajectoryData.cells must have shape (s,3,3), " "with s=number of steps") + numatoms = len(symbols) if positions.shape != (numsteps, numatoms, 3): raise ValueError("TrajectoryData.positions must have shape (s,n,3), " "with s=number of steps and n=number of symbols") @@ -87,33 +91,20 @@ def _internal_validate(self, stepids, cells, symbols, positions, times, velociti "have shape (s,n,3), " "with s=number of steps and n=number of symbols") - def set_trajectory(self, stepids, cells, symbols, positions, times=None, velocities=None): # pylint: disable=too-many-arguments + def set_trajectory(self, symbols, positions, stepids=None, cells=None, times=None, velocities=None): # pylint: disable=too-many-arguments r""" Store the whole trajectory, after checking that types and dimensions are correct. - Velocities are optional, if they are not passed, nothing is stored. - :param stepids: integer array with dimension ``s``, where ``s`` is the - number of steps. Typically represents an internal counter - within the code. For instance, if you want to store a - trajectory with one step every 10, starting from step 65, - the array will be ``[65,75,85,...]``. - No checks are done on duplicate elements - or on the ordering, but anyway this array should be - sorted in ascending order, without duplicate elements. - If your code does not provide an internal counter, just - provide for instance ``arange(s)``. - It is internally stored as an array named 'steps'. - :param cells: float array with dimension :math:`s \times 3 \times 3`, - where ``s`` is the - length of the ``stepids`` array. Units are angstrom. - In particular, - ``cells[i,j,k]`` is the ``k``-th component of the ``j``-th - cell vector at the time step with index ``i`` (identified - by step number ``stepid[i]`` and with timestamp ``times[i]``). - :param symbols: string array with dimension ``n``, where ``n`` is the + Parameters ``stepids``, ``cells`` and ``velocities`` are optional + variables. If nothing is passed for ``cells`` or ``velocities`` + nothing will be stored. However, if no input is given for ``stepids`` + a consecutive sequence [0,1,2,...,len(positions)-1] will be assumed. + + + :param symbols: string list with dimension ``n``, where ``n`` is the number of atoms (i.e., sites) in the structure. - The same array is used for each step. Normally, the string + The same list is used for each step. Normally, the string should be a valid chemical symbol, but actually any unique string works and can be used as the name of the atomic kind (see also the :py:meth:`.get_step_structure()` method). @@ -126,6 +117,23 @@ def set_trajectory(self, stepids, cells, symbols, positions, times=None, velocit ``j``-th atom (or site) in the structure at the time step with index ``i`` (identified by step number ``step[i]`` and with timestamp ``times[i]``). + :param stepids: integer array with dimension ``s``, where ``s`` is the + number of steps. Typically represents an internal counter + within the code. For instance, if you want to store a + trajectory with one step every 10, starting from step 65, + the array will be ``[65,75,85,...]``. + No checks are done on duplicate elements + or on the ordering, but anyway this array should be + sorted in ascending order, without duplicate elements. + (If not specified, stepids will be set to ``numpy.arange(s)`` + by default) It is internally stored as an array named 'steps'. + :param cells: if specified float array with dimension + :math:`s \times 3 \times 3`, where ``s`` is the + length of the ``stepids`` array. Units are angstrom. + In particular, ``cells[i,j,k]`` is the ``k``-th component + of the ``j``-th cell vector at the time step with index + ``i`` (identified by step number ``stepid[i]`` and with + timestamp ``times[i]``). :param times: if specified, float array with dimension ``s``, where ``s`` is the length of the ``stepids`` array. Contains the timestamp of each step in picoseconds (ps). @@ -135,11 +143,25 @@ def set_trajectory(self, stepids, cells, symbols, positions, times=None, velocit .. todo :: Choose suitable units for velocities """ + + import numpy + self._internal_validate(stepids, cells, symbols, positions, times, velocities) - self.set_array('steps', stepids) - self.set_array('cells', cells) - self.set_array('symbols', symbols) + # set symbols as attribute for easier querying + self._set_attr('symbols', list(symbols)) self.set_array('positions', positions) + if stepids is not None: # use input stepids + self.set_array('steps', stepids) + else: # use consecutive sequence if not given + self.set_array('steps', numpy.arange(positions.shape[0])) + if cells is not None: + self.set_array('cells', cells) + else: + # Delete cells array, if it was present + try: + self.delete_array('cells') + except KeyError: + pass if times is not None: self.set_array('times', times) else: @@ -176,9 +198,9 @@ def set_structurelist(self, structurelist): for symbols_now in [[str(s.kind_name) for s in structurelist[i].sites] for i in stepids]: if symbols_first != symbols_now: raise ValueError("Symbol lists have to be the same for all of the supplied structures") - symbols = numpy.array(symbols_first) + symbols = list(symbols_first) positions = numpy.array([[list(s.position) for s in x.sites] for x in structurelist]) - self.set_trajectory(stepids, cells, symbols, positions) + self.set_trajectory(stepids=stepids, cells=cells, symbols=symbols, positions=positions) def _validate(self): """ @@ -189,7 +211,7 @@ def _validate(self): from aiida.common.exceptions import ValidationError try: - self._internal_validate(self.get_stepids(), self.get_cells(), self.get_symbols(), self.get_positions(), + self._internal_validate(self.get_stepids(), self.get_cells(), self.symbols, self.get_positions(), self.get_times(), self.get_velocities()) # Should catch TypeErrors, ValueErrors, and KeyErrors for missing arrays except Exception as exception: @@ -212,7 +234,7 @@ def numsites(self): Return the number of stored sites, or zero if nothing has been stored yet. """ try: - return self.get_shape('symbols')[0] + return len(self.symbols) except (AttributeError, KeyError, IndexError): return 0 @@ -244,15 +266,19 @@ def get_cells(self): :raises KeyError: if the trajectory has not been set yet. """ - return self.get_array('cells') + try: + return self.get_array('cells') + except (AttributeError, KeyError): + return None - def get_symbols(self): + @property + def symbols(self): """ Return the array of symbols, if it has already been set. :raises KeyError: if the trajectory has not been set yet. """ - return self.get_array('symbols') + return self.get_attr('symbols') def get_positions(self): """ @@ -331,8 +357,10 @@ def get_step_data(self, index): time = self.get_times() if time is not None: time = time[index] - return (self.get_stepids()[index], time, self.get_cells()[index, :, :], self.get_symbols(), - self.get_positions()[index, :, :], vel) + cells = self.get_cells() + if cells is not None: + cell = cells[index, :, :] + return (self.get_stepids()[index], time, cell, self.symbols, self.get_positions()[index, :, :], vel) def get_step_structure(self, index, custom_kinds=None): """ @@ -403,11 +431,13 @@ def _prepare_xsf(self, index=None, main_file_name=""): # pylint: disable=unused return_string = "ANIMSTEPS {}\nCRYSTAL\n".format(len(indices)) # Do the checks once and for all here: structure = self.get_step_structure(index=0) - if structure.is_alloy() or structure.has_vacancies(): + if structure.is_alloy or structure.has_vacancies: raise NotImplementedError("XSF for alloys or systems with vacancies not implemented.") cells = self.get_cells() + if cells is None: + raise ValueError("No cell parameters have been supplied for " "TrajectoryData") positions = self.get_positions() - symbols = self.get_symbols() + symbols = self.symbols atomic_numbers_list = [_atomic_numbers[s] for s in symbols] nat = len(symbols) @@ -415,7 +445,7 @@ def _prepare_xsf(self, index=None, main_file_name=""): # pylint: disable=unused return_string += "PRIMVEC {}\n".format(idx + 1) #~ structure = self.get_step_structure(index=idx) #~ sites = structure.sites - #~ if structure.is_alloy() or structure.has_vacancies(): + #~ if structure.is_alloy or structure.has_vacancies: #~ raise NotImplementedError("XSF for alloys or systems with " #~ "vacancies not implemented.") for cell_vector in cells[idx]: @@ -461,6 +491,24 @@ def _get_aiida_structure(self, store=False, **kwargs): """ Creates :py:class:`aiida.orm.data.structure.StructureData`. + :param converter: specify the converter. Default 'ase'. + :param store: If True, intermediate calculation gets stored in the + AiiDA database for record. Default False. + :return: :py:class:`aiida.orm.data.structure.StructureData` node. + """ + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn( # pylint: disable=no-member + 'This method has been deprecated and will be renamed to get_structure() in AiiDA v1.0', DeprecationWarning) + return self.get_structure(store=store, **kwargs) + + def get_structure(self, store=False, **kwargs): + """ + Creates :py:class:`aiida.orm.data.structure.StructureData`. + + .. versionadded:: 1.0 + Renamed from _get_aiida_structure + :param converter: specify the converter. Default 'ase'. :param store: If True, intermediate calculation gets stored in the AiiDA database for record. Default False. @@ -477,8 +525,21 @@ def _get_cif(self, index=None, **kwargs): """ Creates :py:class:`aiida.orm.data.cif.CifData` """ - struct = self._get_aiida_structure(index=index, **kwargs) - cif = struct._get_cif(**kwargs) # pylint: disable=protected-access + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn( # pylint: disable=no-member + 'This method has been deprecated and will be renamed to get_cif() in AiiDA v1.0', DeprecationWarning) + return self.get_cif(index=index, **kwargs) + + def get_cif(self, index=None, **kwargs): + """ + Creates :py:class:`aiida.orm.data.cif.CifData` + + .. versionadded:: 1.0 + Renamed from _get_cif + """ + struct = self.get_structure(index=index, **kwargs) + cif = struct.get_cif(**kwargs) # pylint: disable=protected-access return cif def _parse_xyz_pos(self, inputstring): @@ -579,7 +640,7 @@ def show_mpl_pos(self, **kwargs): # pylint: disable=too-many-locals # Reading the arrays I need: positions = self.get_positions() times = self.get_times() - symbols = self.get_symbols() + symbols = self.symbols # Try to get the units. try: @@ -708,11 +769,15 @@ def collapse_into_unit_cell(point, cell): except KeyError: pass - symbols = self.get_symbols() + symbols = self.symbols if elements is None: elements = set(symbols) - cell = np.array(self.get_cells()[0]) + cells = self.get_cells() + if cells is None: + raise ValueError("No cell parameters have been supplied for " "TrajectoryData") + else: + cell = np.array(cells[0]) storage_dict = {s: {} for s in elements} for ele in elements: storage_dict[ele] = [np.array([]), np.array([]), np.array([])] diff --git a/aiida/orm/data/cif.py b/aiida/orm/data/cif.py index ebb307a884..d54604937c 100644 --- a/aiida/orm/data/cif.py +++ b/aiida/orm/data/cif.py @@ -420,7 +420,6 @@ def parse_formula(formula): return contents -# pylint: disable=abstract-method # Note: Method 'query' is abstract in class 'Node' but is not overridden class CifData(SinglefileData): """ @@ -431,6 +430,7 @@ class CifData(SinglefileData): when setting ``ase`` or ``values``, a physical CIF file is generated first, the values are updated from the physical CIF file. """ + # pylint: disable=abstract-method, too-many-public-methods _set_incompatibilities = [('ase', 'file'), ('ase', 'values'), ('file', 'values')] _scan_types = ['standard', 'flex'] _parse_policies = ['eager', 'lazy'] @@ -837,6 +837,30 @@ def _get_aiida_structure(self, converter='pymatgen', store=False, **kwargs): """ Creates :py:class:`aiida.orm.data.structure.StructureData`. + :param converter: specify the converter. Default 'pymatgen'. + :param store: if True, intermediate calculation gets stored in the + AiiDA database for record. Default False. + :param primitive_cell: if True, primitive cell is returned, + conventional cell if False. Default False. + :param occupancy_tolerance: If total occupancy of a site is between 1 and occupancy_tolerance, + the occupancies will be scaled down to 1. (pymatgen only) + :param site_tolerance: This tolerance is used to determine if two sites are sitting in the same position, + in which case they will be combined to a single disordered site. Defaults to 1e-4. (pymatgen only) + :return: :py:class:`aiida.orm.data.structure.StructureData` node. + """ + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn( # pylint: disable=no-member + 'This method has been deprecated and will be renamed to get_structure() in AiiDA v1.0', DeprecationWarning) + return self.get_structure(converter=converter, store=store, **kwargs) + + def get_structure(self, converter='pymatgen', store=False, **kwargs): + """ + Creates :py:class:`aiida.orm.data.structure.StructureData`. + + .. versionadded:: 1.0 + Renamed from _get_aiida_structure + :param converter: specify the converter. Default 'pymatgen'. :param store: if True, intermediate calculation gets stored in the AiiDA database for record. Default False. diff --git a/aiida/orm/data/code.py b/aiida/orm/data/code.py index d324e74024..86b0786b89 100644 --- a/aiida/orm/data/code.py +++ b/aiida/orm/data/code.py @@ -59,7 +59,8 @@ def reveal(self): """ self.set_extra(self.HIDDEN_KEY, False) - def is_hidden(self): + @property + def hidden(self): """ Determines whether the Code is hidden or not """ @@ -514,6 +515,15 @@ def get_builder(self): return builder def full_text_info(self, verbose=False): + """ + Return a (multiline) string with a human-readable detailed information on this computer + """ + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn('This method has been deprecated and will be renamed to get_full_text_info() in AiiDA v1.0', DeprecationWarning) + return self.get_full_text_info(verbose=verbose) + + def get_full_text_info(self, verbose=False): """ Return a (multiline) string with a human-readable detailed information on this computer """ diff --git a/aiida/orm/data/remote.py b/aiida/orm/data/remote.py index 43091ae276..3336dad597 100644 --- a/aiida/orm/data/remote.py +++ b/aiida/orm/data/remote.py @@ -43,6 +43,7 @@ def add_path(self, src_abs, dst_filename=None): raise ModificationNotAllowed("Cannot add files or directories to a RemoteData object") + @property def is_empty(self): """ Check if remote folder is empty diff --git a/aiida/orm/data/structure.py b/aiida/orm/data/structure.py index 2c0500592f..6fe709921c 100644 --- a/aiida/orm/data/structure.py +++ b/aiida/orm/data/structure.py @@ -997,7 +997,7 @@ def _prepare_xsf(self, main_file_name=""): """ Write the given structure to a string of format XSF (for XCrySDen). """ - if self.is_alloy() or self.has_vacancies(): + if self.is_alloy or self.has_vacancies: raise NotImplementedError("XSF for alloys or systems with " "vacancies not implemented.") @@ -1111,7 +1111,7 @@ def _prepare_xyz(self, main_file_name=""): """ Write the given structure to a string of format XYZ. """ - if self.is_alloy() or self.has_vacancies(): + if self.is_alloy or self.has_vacancies: raise NotImplementedError("XYZ for alloys or systems with " "vacancies not implemented.") @@ -1857,21 +1857,23 @@ def cell_angles(self, value): def set_cell_angles(self, value): raise NotImplementedError("Modification is not implemented yet") + @property def is_alloy(self): """ To understand if there are alloys in the structure. :return: a boolean, True if at least one kind is an alloy """ - return any(s.is_alloy() for s in self.kinds) + return any(s.is_alloy for s in self.kinds) + @property def has_vacancies(self): """ To understand if there are vacancies in the structure. :return: a boolean, True if at least one kind has a vacancy """ - return any(s.has_vacancies() for s in self.kinds) + return any(s.has_vacancies for s in self.kinds) def get_cell_volume(self): """ @@ -1885,6 +1887,23 @@ def _get_cif(self, converter='ase', store=False, **kwargs): """ Creates :py:class:`aiida.orm.data.cif.CifData`. + :param converter: specify the converter. Default 'ase'. + :param store: If True, intermediate calculation gets stored in the + AiiDA database for record. Default False. + :return: :py:class:`aiida.orm.data.cif.CifData` node. + """ + import warnings + from aiida.common.warnings import AiidaDeprecationWarning as DeprecationWarning # pylint: disable=redefined-builtin + warnings.warn('This method has been deprecated and will be renamed to get_cif() in AiiDA v1.0', DeprecationWarning) + return self.get_cif(converter=converter, store=store, **kwargs) + + def get_cif(self, converter='ase', store=False, **kwargs): + """ + Creates :py:class:`aiida.orm.data.cif.CifData`. + + .. versionadded:: 1.0 + Renamed from _get_cif + :param converter: specify the converter. Default 'ase'. :param store: If True, intermediate calculation gets stored in the AiiDA database for record. Default False. @@ -2196,7 +2215,7 @@ def get_raw(self): # raised (from the site.get_ase() routine). # """ # import ase - # if self.is_alloy() or self.has_vacancies(): + # if self.is_alloy or self.has_vacancies: # raise ValueError("Cannot convert to ASE if the site is an alloy " # "or has vacancies.") # aseatom = ase.Atom(position=[0.,0.,0.], symbol=self.symbols[0], @@ -2421,6 +2440,7 @@ def set_symbols_and_weights(self, symbols, weights): self._symbols = symbols_tuple self._weights = weights_tuple + @property def is_alloy(self): """ To understand if kind is an alloy. @@ -2430,6 +2450,7 @@ def is_alloy(self): """ return len(self._symbols) != 1 + @property def has_vacancies(self): """ Returns True if the sum of the weights is less than one. @@ -2530,7 +2551,7 @@ def get_ase(self, kinds): used_tags = defaultdict(list) for k in kinds: # Skip alloys and vacancies - if k.is_alloy() or k.has_vacancies(): + if k.is_alloy or k.has_vacancies: tag_list.append(None) # If the kind name is equal to the specie name, # then no tag should be set @@ -2575,7 +2596,7 @@ def get_ase(self, kinds): raise ValueError("No kind '{}' has been found in the list of kinds" "".format(self.kind_name)) - if kind.is_alloy() or kind.has_vacancies(): + if kind.is_alloy or kind.has_vacancies: raise ValueError("Cannot convert to ASE if the kind represents " "an alloy or it has vacancies.") aseatom = ase.Atom(position=self.position, diff --git a/aiida/tools/dbexporters/tcod.py b/aiida/tools/dbexporters/tcod.py index b2039b9415..c0b6bc246b 100644 --- a/aiida/tools/dbexporters/tcod.py +++ b/aiida/tools/dbexporters/tcod.py @@ -981,7 +981,7 @@ def export_cifnode(what, parameters=None, trajectory_index=None, """ The main exporter function. Exports given coordinate-containing \*Data node to :py:class:`aiida.orm.data.cif.CifData` node, ready to be - exported to TCOD. All \*Data types, having method ``_get_cif()``, are + exported to TCOD. All \*Data types, having method ``get_cif()``, are supported in addition to :py:class:`aiida.orm.data.cif.CifData`. :param what: data node to be exported. @@ -1038,11 +1038,11 @@ def export_cifnode(what, parameters=None, trajectory_index=None, # Convert node to CifData (if required) - if not isinstance(node, CifData) and getattr(node, '_get_cif'): + if not isinstance(node, CifData) and getattr(node, 'get_cif'): function_args = {'store': store} if trajectory_index is not None: function_args['index'] = trajectory_index - node = node._get_cif(**function_args) + node = node.get_cif(**function_args) if not isinstance(node,CifData): raise NotImplementedError("Exporter does not know how to " diff --git a/aiida/tools/dbimporters/baseclasses.py b/aiida/tools/dbimporters/baseclasses.py index f64a0afae7..29fe147a5b 100644 --- a/aiida/tools/dbimporters/baseclasses.py +++ b/aiida/tools/dbimporters/baseclasses.py @@ -321,7 +321,7 @@ def get_aiida_structure(self, converter="pymatgen", store=False, **kwargs): """ cif = self.get_cif_node(store=store, parse_policy='lazy') - return cif._get_aiida_structure(converter=converter, store=store, **kwargs) + return cif.get_structure(converter=converter, store=store, **kwargs) def get_parsed_cif(self): """ diff --git a/docs/source/concepts/workflows.rst b/docs/source/concepts/workflows.rst index 99a6f514da..9b1fc64c07 100644 --- a/docs/source/concepts/workflows.rst +++ b/docs/source/concepts/workflows.rst @@ -913,3 +913,15 @@ However, these workchains can be updated with just a few minor updates that we w * The import ``aiida.work.workfunction.workfunction`` has been moved to ``aiida.work.process_function.workfunction``. * The ``input_group`` has been deprecated and been replaced by namespaces. See the section on :ref:`port namespaces` on how to use them. * The use of a ``.`` (period) in output keys is not supported in ``Process.out`` because that is now reserved to indicate namespaces. +* The method ``ArrayData.iterarrayas()`` has been renamed to ``ArrayData.get_iterarrays()``. +* The method ``TrajectoryData._get_cif()`` has been renamed to ``TrajectoryData.get_cif()``. +* The method ``TrajectoryData._get_aiida_structure()`` has been renamed to ``TrajectoryData.get_structure()``. +* The method ``StructureData._get_cif()`` has been renamed to ``StructureData.get_cif()``. +* The method ``Code.full_text_info()`` has been renamed to ``Code.get_full_text_info()``. +* The method ``Code.is_hidden()`` has been changed and is now accessed through the ``Code.hidden`` property. +* The method ``RemoteData.is_empty()`` has been changes and is now accessed through the ``RemoteData.is_empty``. +* The method ``.is_alloy()`` for classes ``StructureData`` and ``Kind`` is now accessed through the ``.is_alloy`` property. +* The method ``.has_vacancies()`` for classes ``StructureData`` and ``Kind`` is now accessed through the ``.has_vacancies`` property. +* The arguments ``stepids`` and ``cells`` of the :meth:`TrajectoryData.set_trajectory()` method are made optional + which has implications on the ordering of the arguments passed to this method. +* The list of atomic symbols for trajectories is no longer stored as array data but is now accessible through the ``TrajectoryData.symbols`` attribute.