def test_direc_and_neg_dims(): for dims in [(2, 3, 4), (-2, -3, -4), (-2, 3, 4), (2, -3, 4), (2, 3, -4)]: m1 = crys.scell_mask(*dims, direc=1)[::-1, :] m2 = crys.scell_mask(*dims, direc=-1) assert (m1 == m2).all() for direc in [1, -1]: ref = crys.scell_mask(2, 3, 4, direc=direc) assert ((ref + crys.scell_mask(-2, -3, -4, direc=direc)) == 0.0).all() now = crys.scell_mask(-2, 3, 4, direc=direc) assert ((ref[:, 0] + now[:, 0]) == 0.0).all() assert (ref[:, 1:] == now[:, 1:]).all() now = crys.scell_mask(2, -3, 4, direc=direc) assert ((ref[:, 1] + now[:, 1]) == 0.0).all() assert (ref[:, (0, 2)] == now[:, (0, 2)]).all() now = crys.scell_mask(2, 3, -4, direc=direc) assert ((ref[:, 2] + now[:, 2]) == 0.0).all() assert (ref[:, :2] == now[:, :2]).all() natoms = 20 coords_frac = rand(natoms, 3) cell = rand(3, 3) dims = (2, 3, 4) symbols = [next(syms) for ii in range(natoms)] struct = Structure(coords_frac=coords_frac, cell=cell, symbols=symbols) # coords are offset by a constant shift if all dims and direc are < 0 s1 = crys.scell(struct, (2, 3, 4), direc=1) s2 = crys.scell(struct, (-2, -3, -4), direc=-1) d = s1.coords - s2.coords assert np.abs(d - d[0, :][None, :]).sum() < 1e-12
def test_get_traj(): st = Structure(coords_frac=rand(20, 3), symbols=['H'] * 20, forces=rand(20, 3), stress=rand(3, 3), etot=42.23) nstep = 5 tr = st.get_traj(nstep) for name in st.attr_lst: print(name) attr = getattr(tr, name) if attr is not None: if name in tr.attrs_nstep: assert attr.shape[tr.timeaxis] == nstep else: attr_st = getattr(st, name) assert_all_types_equal(attr, attr_st)
def test_get_traj(): st = Structure(coords_frac=rand(20,3), symbols=['H']*20, forces=rand(20,3), stress=rand(3,3), etot=42.23) nstep = 5 tr = st.get_traj(nstep) for name in st.attr_lst: print name attr = getattr(tr, name) if attr is not None: if name in tr.attrs_nstep: assert attr.shape[tr.timeaxis] == nstep else: attr_st = getattr(st, name) assert_all_types_equal(attr, attr_st)
def test_mix(): symbols = ['H'] * 3 + ['Au'] * 7 natoms = len(symbols) st1nf = Structure(coords_frac=rand(natoms, 3), symbols=symbols, cell=rand(3, 3)) st2nf = Structure(coords_frac=rand(natoms, 3), symbols=symbols, cell=rand(3, 3)) st1f = Structure(coords_frac=rand(natoms, 3), symbols=symbols, cell=rand(3, 3), forces=rand(natoms, 3)) st2f = Structure(coords_frac=rand(natoms, 3), symbols=symbols, cell=rand(3, 3), forces=rand(natoms, 3)) for st1, st2 in [(st1f, st2f), (st1nf, st2nf)]: tr = crys.mix(st1, st2, alpha=np.linspace(0, 1, 20)) assert tr.nstep == 20 assert tr.coords_frac.shape == (20, st1.natoms, 3) for idx, st in [(0, st1), (-1, st2)]: tools.assert_dict_with_all_types_almost_equal(st.__dict__, tr[idx].__dict__, keys=st1.attr_lst) for x in [0.5, 0.9]: tr = crys.mix(st1, st2, alpha=np.array([x])) assert tr.nstep == 1 tools.assert_all_types_almost_equal( tr[0].coords, (1 - x) * st1.coords + x * st2.coords) tools.assert_all_types_almost_equal( tr[0].cell, (1 - x) * st1.cell + x * st2.cell) if tr.forces is not None: tools.assert_all_types_almost_equal( tr[0].forces, (1 - x) * st1.forces + x * st2.forces)
def test_nn(): # make cell big enough to avoid pbc wrap, we only test cases where pbc=True # == pbc=False, we trust that pbc distances work, see crys.rpdf() etc cell = np.identity(3) * 10 xcoords = np.array(\ [ 1, 2.02, 3.1, 4, 4.9, 6.01, 7.03]) symbols = \ ['H', 'H', 'O', 'Ca', 'O', 'Cl', 'Cl'] coords = np.zeros((len(xcoords), 3), dtype=float) coords[:, 0] = xcoords struct = Structure(coords=coords, cell=cell, symbols=symbols) asym = np.array(struct.symbols) # [2, 4, 1, 5, 0, 6] assert aequal(nearest_neighbors(struct, idx=3, num=2), np.array([2, 4])) # [1, 5, 0, 6] assert aequal(nearest_neighbors(struct, idx=3, num=2, skip='O'), np.array([1, 5])) # [1, 0] assert aequal(nearest_neighbors(struct, idx=3, num=2, skip=['O', 'Cl']), np.array([1, 0])) # [2, 4] assert aequal(nearest_neighbors(struct, idx=3, cutoff=1.2), np.array([2, 4])) # [] assert aequal(nearest_neighbors(struct, idx=3, cutoff=1.2, skip='O'), np.array([])) # [2,4,1,5] assert aequal(nearest_neighbors(struct, idx=3, cutoff=2.1, skip=None), np.array([2, 4, 1, 5])) # [1] assert aequal( nearest_neighbors(struct, idx=3, cutoff=2.1, skip=['O', 'Cl']), np.array([1])) # [1,0], with dist d = nearest_neighbors(struct, idx=3, num=2, skip=['O', 'Cl'], fullout=True)[1] np.allclose(d, np.array([1.98, 3.0]))
def _get_random_struct(self): """Generate random cryst_const and atom coords. Returns ------- Structure Raises ------ RandomStructureFail """ self.cell = cc2cell(self.get_random_cryst_const()) self.coords_frac = np.empty((self.natoms, 3)) self.counters['coords'] = [] for iatom in range(self.natoms): if iatom == 0: cnt = 1 self._add_random_atom(iatom) else: cnt = 1 while cnt <= self.atom_maxtry: self._add_random_atom(iatom) if self._atoms_too_close(iatom): self._add_random_atom(iatom) cnt += 1 else: break self.counters['coords'].append(cnt) if cnt > self.atom_maxtry: raise RandomStructureFail("failed to create random coords for " "iatom=%i of %i" % (iatom, self.natoms - 1)) st = Structure(symbols=self.symbols, coords_frac=self.coords_frac, cell=self.cell) return st
def spglib2struct(tup): """Transform returned tuple from various spglib functions to :class:`~pwtools.crys.Structure`. This applies to ``spglib.find_primitive()`` and probably some more. Their doc string says it returns an ``ase.Atoms`` object, but what it actually returns is a tuple `(cell,coords_frac,znucl)`. `znucl` is a list of integers with atomic core charge (e.g. 1 for H), see :data:`pwtools.atomic_data.numbers`. Parameters ---------- tup : tuple (3,) Return value from ``spglib.find_primitive()`` and maybe others. Returns ------- :class:`~pwtools.crys.Structure` """ assert isinstance(tup, tuple) assert len(tup) == 3 symbols = [atomic_data.symbols[ii] for ii in tup[2]] st = Structure(coords_frac=tup[1], cell=tup[0], symbols=symbols) return st
def test_znucl(): st = Structure(symbols=['Al'] * 2 + ['N'] * 3) assert st.znucl == [13] * 2 + [7] * 3 assert st.znucl_unique == [13, 7]
def test_struct(): natoms = 10 cell = np.array([[3, 0, 0], [1.1, 5, -0.04], [-0.33, 1.5, 7]]) cryst_const = crys.cell2cc(cell) coords_frac = rand(natoms, 3) coords = crys.coord_trans(coords=coords_frac, old=cell, new=np.identity(3)) symbols = ['H'] * natoms stress = rand(3, 3) forces = rand(natoms, 3) # Use ``cell`` instead of ``cryst_const` as input such that # atoms.get_cell() test passes (see below for why -- cell orientation) st = Structure(coords_frac=coords_frac, symbols=symbols, cell=cell, stress=stress, forces=forces, etot=42) # Test if all getters work. for name in st.attr_lst: print(name) st.try_set_attr(name) assert getattr(st, name) is not None, "attr None: %s" % name assert eval('st.get_%s()' % name) is not None, "getter returns None: %s" % name aaae(coords_frac, st.coords_frac) aaae(cryst_const, st.cryst_const) aaae(coords, st.coords) assert st.natoms == natoms st = Structure(coords_frac=coords_frac, symbols=symbols, cell=cell) aaae(coords, st.get_coords()) # Cell calculated from cryst_const has defined orientation in space which may be # different from the original `cell`, but the volume and underlying cryst_const # must be the same. st = Structure(coords_frac=coords_frac, symbols=symbols, cryst_const=cryst_const) assert st.get_cell() is not None np.testing.assert_almost_equal(crys.volume_cell(cell), crys.volume_cell(st.get_cell())) aaae(cryst_const, crys.cell2cc(st.get_cell())) # units st = Structure(coords_frac=coords_frac, cell=cell, symbols=symbols, stress=stress, forces=forces, units={ 'length': 2, 'forces': 3, 'stress': 4 }) aaae(2 * coords, st.coords) aaae(3 * forces, st.forces) aaae(4 * stress, st.stress) traj = crys.struct2traj(st) assert traj.is_traj # copy(): Assert everything has another memory location = is a new copy of # the object. IntTypes are NOT copied by copy.deepcopy(), which we use in # Structure.copy(), apparently b/c they are always automatically copied # before in-place operations. Same for float type. # # >>> a=10; b=a; print id(a); print id(b) # 36669152 # 36669152 # >>> a*=100; print id(a); print id(b) # 72538264 # 36669152 # >>> a # 100 # >>> b # 10 # # >>> a=[1,2,3]; b=a; print id(a); print id(b) # 72624320 # 72624320 # >>> a[0] = 44; print id(a); print id(b) # 72624320 # 72624320 # >>> a # [44, 2, 3] # >>> b # [44, 2, 3] st2 = st.copy() for name in st.attr_lst: val = getattr(st, name) if val is not None and not (isinstance(val, int) or \ isinstance(val, float)): val2 = getattr(st2, name) assert id(val2) != id(val) assert_all_types_equal(val2, val)
def test_write_mol(): units = {'forces': Ha / eV} nstep = 2 cell2d = np.random.rand(3, 3) cell3d = np.random.rand(nstep, 3, 3) # fractional coords2d_frac = np.array([[0.5, 0.5, 0.5], [1, 1, 1]]) # fractional, 2 time steps: (2,2,3) = (nstep, natoms, 3) coords3d_frac = np.array([coords2d_frac, coords2d_frac * 0.8]) # cartesian = coords3d_frac + cell2d (fixed cell). For varialbe cell cases # below, cell3d is used! coords3d_cart = crys.coord_trans(coords3d_frac, old=cell2d, new=np.identity(3), axis=-1) coords2d_cart = coords3d_cart[0, ...] symbols = ['H'] * 2 forces2d = np.random.random(coords2d_frac.shape) forces3d = np.random.random(coords3d_frac.shape) # --- AXSF --------------------------------------------------------------- # fixed cell, forces=0 axsf_fn = pj(testdir, 'foo.axsf') io.write_axsf( axsf_fn, Trajectory(units=units, coords_frac=coords3d_frac, cell=cell2d, symbols=symbols), ) arr = np.loadtxt( StringIO( common.backtick("grep -A3 PRIMVEC %s | grep -vE -e '--|PRIMVEC'" % axsf_fn))) np.testing.assert_array_almost_equal( arr, np.concatenate((cell2d, cell2d), axis=0)) arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % axsf_fn))) arr2 = np.vstack((coords3d_cart[0, ...], coords3d_cart[1, ...])) np.testing.assert_array_almost_equal(arr, arr2) # fixed cell, forces3d, coords_frac axsf_fn = pj(testdir, 'foo3.axsf') io.write_axsf( axsf_fn, Trajectory(units=units, coords_frac=coords3d_frac, cell=cell2d, symbols=symbols, forces=forces3d), ) arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % axsf_fn))) t0 = np.concatenate((coords3d_cart[0, ...], forces3d[0, ...]), axis=-1) t1 = np.concatenate((coords3d_cart[1, ...], forces3d[1, ...]), axis=-1) arr2 = np.vstack((t0, t1)) print(arr) print(arr2) print("----------------") np.testing.assert_array_almost_equal(arr, arr2) # variable cell, forces3d, coords_frac axsf_fn = pj(testdir, 'foo4.axsf') io.write_axsf( axsf_fn, Trajectory(units=units, coords_frac=coords3d_frac, cell=cell3d, symbols=symbols, forces=forces3d)) arr = np.loadtxt( StringIO( common.backtick( "grep -A3 PRIMVEC %s | grep -v -e '--' -e 'PRIMVEC'" % axsf_fn))) arr2 = np.vstack((cell3d[0, ...], cell3d[1, ...])) print(arr) print(arr2) print("----------------") np.testing.assert_array_almost_equal(arr, arr2) arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % axsf_fn))) t0 = np.concatenate( (np.dot(coords3d_frac[0, ...], cell3d[0, ...]), forces3d[0, ...]), axis=-1) t1 = np.concatenate( (np.dot(coords3d_frac[1, ...], cell3d[1, ...]), forces3d[1, ...]), axis=-1) arr2 = np.vstack((t0, t1)) print(arr) print(arr2) print("----------------") np.testing.assert_array_almost_equal(arr, arr2) # single struct, coords_cart axsf_fn = pj(testdir, 'foo6.axsf') io.write_axsf( axsf_fn, Structure(units=units, coords=coords2d_cart, cell=cell2d, symbols=symbols, forces=forces2d)) arr = np.loadtxt( StringIO( common.backtick( "grep -A3 PRIMVEC %s | grep -v -e '--' -e 'PRIMVEC'" % axsf_fn))) arr2 = cell2d print(arr) print(arr2) print("----------------") np.testing.assert_array_almost_equal(arr, arr2) arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % axsf_fn))) arr2 = np.concatenate((coords2d_cart, forces2d), axis=1) print(arr) print(arr2) print("----------------") np.testing.assert_array_almost_equal(arr, arr2) # --- XYZ ---------------------------------------------------------------- # Use cell, coords, etc from above # input: coords_frac xyz_fn = pj(testdir, 'foo_frac_input.xyz') io.write_xyz(xyz_fn, Trajectory(units=units, coords_frac=coords3d_frac, cell=cell2d, symbols=symbols), name='foo') arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % xyz_fn))) arr2 = np.concatenate([coords3d_cart[0, ...], coords3d_cart[1, ...]], axis=0) np.testing.assert_array_almost_equal(arr, arr2) # input: coords_cart, cell=None xyz_fn = pj(testdir, 'foo_cart_input.xyz') io.write_xyz(xyz_fn, Trajectory(units=units, coords=coords3d_cart, symbols=symbols), name='foo') arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % xyz_fn))) arr2 = np.concatenate((coords3d_cart[0, ...], coords3d_cart[1, ...]), axis=0) np.testing.assert_array_almost_equal(arr, arr2) # input: coords2d_frac, cell=cell2d xyz_fn = pj(testdir, 'foo_cart_input.xyz') io.write_xyz(xyz_fn, Structure(units=units, coords_frac=coords2d_frac, cell=cell2d, symbols=symbols), name='foo') arr = np.loadtxt( StringIO(common.backtick("sed -nre 's/^H(.*)/\\1/gp' %s" % xyz_fn))) arr2 = coords2d_cart np.testing.assert_array_almost_equal(arr, arr2)
def test_scell(): cell = np.identity(3) coords_frac = np.array([[0.5, 0.5, 0.5], [1, 1, 1]]) symbols = ['Al', 'N'] sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=symbols), (2, 2, 2)) sc_coords_frac = \ np.array([[ 0.25, 0.25, 0.25], [ 0.25, 0.25, 0.75], [ 0.25, 0.75, 0.25], [ 0.25, 0.75, 0.75], [ 0.75, 0.25, 0.25], [ 0.75, 0.25, 0.75], [ 0.75, 0.75, 0.25], [ 0.75, 0.75, 0.75], [ 0.5 , 0.5 , 0.5 ], [ 0.5 , 0.5 , 1. ], [ 0.5 , 1. , 0.5 ], [ 0.5 , 1. , 1. ], [ 1. , 0.5 , 0.5 ], [ 1. , 0.5 , 1. ], [ 1. , 1. , 0.5 ], [ 1. , 1. , 1. ]]) sc_symbols = ['Al'] * 8 + ['N'] * 8 sc_cell = \ np.array([[ 2., 0., 0.], [ 0., 2., 0.], [ 0., 0., 2.]]) assert sc.symbols == sc_symbols np.testing.assert_array_almost_equal(sc.coords_frac, sc_coords_frac) np.testing.assert_array_almost_equal(sc.cell, sc_cell) # non-orthorhombic cell cell = \ np.array([[ 1., 0.5, 0.5], [ 0.25, 1., 0.2], [ 0.2, 0.5, 1.]]) sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=symbols), (2, 2, 2)) sc_cell = \ np.array([[ 2. , 1. , 1. ], [ 0.5, 2. , 0.4], [ 0.4, 1. , 2. ]]) np.testing.assert_array_almost_equal(sc.cell, sc_cell) # crystal coords are cell-independent np.testing.assert_array_almost_equal(sc.coords_frac, sc_coords_frac) # slab # # Test if old and new implementation behave for a tricky case: natoms == 2 # mask.shape[0], i.e. if reshape() behaves correctly. # Reference generated with old implementation. Default is new. cell = np.identity(3) coords_frac = np.array([[0.5, 0.5, 0.5], [1, 1, 1]]) symbols = ['Al', 'N'] sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=symbols), (1, 1, 2)) sc_coords_frac = \ np.array([[ 0.5 , 0.5 , 0.25], [ 0.5 , 0.5 , 0.75], [ 1. , 1. , 0.5 ], [ 1. , 1. , 1. ]]) sc_cell = \ np.array([[ 1., 0., 0.], [ 0., 1., 0.], [ 0., 0., 2.]]) sc_symbols = ['Al', 'Al', 'N', 'N'] assert sc.symbols == sc_symbols np.testing.assert_array_almost_equal(sc.cell, sc_cell) np.testing.assert_array_almost_equal(sc.coords_frac, sc_coords_frac) sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=symbols), (1, 2, 1)) sc_coords_frac = \ np.array([[ 0.5 , 0.25, 0.5 ], [ 0.5 , 0.75, 0.5 ], [ 1. , 0.5 , 1. ], [ 1. , 1. , 1. ]]) sc_cell = \ np.array([[ 1., 0., 0.], [ 0., 2., 0.], [ 0., 0., 1.]]) assert sc.symbols == sc_symbols np.testing.assert_array_almost_equal(sc.cell, sc_cell) np.testing.assert_array_almost_equal(sc.coords_frac, sc_coords_frac) sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=symbols), (2, 1, 1)) sc_coords_frac = \ np.array([[ 0.25, 0.5 , 0.5 ], [ 0.75, 0.5 , 0.5 ], [ 0.5 , 1. , 1. ], [ 1. , 1. , 1. ]]) sc_cell = \ np.array([[ 2., 0., 0.], [ 0., 1., 0.], [ 0., 0., 1.]]) assert sc.symbols == sc_symbols np.testing.assert_array_almost_equal(sc.cell, sc_cell) np.testing.assert_array_almost_equal(sc.coords_frac, sc_coords_frac) # symbols = None sc = crys.scell( Structure(coords_frac=coords_frac, cell=cell, symbols=None), (2, 2, 2)) assert sc.symbols is None # Trajectory natoms = 4 nstep = 100 symbols = [next(syms) for ii in range(natoms)] # cell 2d coords_frac = rand(nstep, natoms, 3) cell = rand(3, 3) dims = (2, 3, 4) nmask = np.prod(dims) sc = crys.scell(Trajectory(coords_frac=coords_frac, cell=cell, symbols=symbols), dims=dims) assert sc.coords_frac.shape == (nstep, nmask * natoms, 3) assert sc.symbols == common.flatten([[sym] * nmask for sym in symbols]) assert sc.cell.shape == (nstep, 3, 3) np.testing.assert_array_almost_equal( sc.cell, num.extend_array(cell * np.asarray(dims)[:, None], sc.nstep, axis=0)) # cell 3d cell = rand(nstep, 3, 3) sc = crys.scell(Trajectory(coords_frac=coords_frac, cell=cell, symbols=symbols), dims=dims) assert sc.coords_frac.shape == (nstep, nmask * natoms, 3) coords_frac2 = np.array([crys.scell(Structure(coords_frac=coords_frac[ii,...,], cell=cell[ii,...], symbols=symbols), dims=dims).coords_frac \ for ii in range(nstep)]) np.testing.assert_array_almost_equal(sc.coords_frac, coords_frac2) assert sc.symbols == common.flatten([[sym] * nmask for sym in symbols]) assert sc.cell.shape == (nstep, 3, 3) np.testing.assert_array_almost_equal( sc.cell, cell * np.asarray(dims)[None, :, None]) # methods natoms = 20 coords_frac = rand(natoms, 3) cell = rand(3, 3) dims = (2, 3, 4) symbols = [next(syms) for ii in range(natoms)] struct = Structure(coords_frac=coords_frac, cell=cell, symbols=symbols) sc1 = crys.scell(struct, dims=dims, method=1) sc2 = crys.scell(struct, dims=dims, method=2) d1 = dict([(key, getattr(sc1, key)) for key in sc1.attr_lst]) d2 = dict([(key, getattr(sc2, key)) for key in sc2.attr_lst]) tools.assert_dict_with_all_types_almost_equal(d1, d2)
def test_struct(): natoms = 10 cell = np.array([[3,0,0], [1.1,5,-0.04], [-0.33,1.5,7]]) cryst_const = crys.cell2cc(cell) coords_frac = rand(natoms,3) coords = crys.coord_trans(coords=coords_frac, old=cell, new=np.identity(3)) symbols = ['H']*natoms stress = rand(3,3) forces = rand(natoms,3) # Use ``cell`` instead of ``cryst_const` as input such that # atoms.get_cell() test passes (see below for why -- cell orientation) st = Structure(coords_frac=coords_frac, symbols=symbols, cell=cell, stress=stress, forces=forces, etot=42) # Test if all getters work. for name in st.attr_lst: print name st.try_set_attr(name) assert getattr(st, name) is not None, "attr None: %s" %name assert eval('st.get_%s()'%name) is not None, "getter returns None: %s" %name aaae(coords_frac, st.coords_frac) aaae(cryst_const, st.cryst_const) aaae(coords, st.coords) assert st.natoms == natoms st = Structure(coords_frac=coords_frac, symbols=symbols, cell=cell) aaae(coords, st.get_coords()) # Cell calculated from cryst_const has defined orientation in space which may be # different from the original `cell`, but the volume and underlying cryst_const # must be the same. st = Structure(coords_frac=coords_frac, symbols=symbols, cryst_const=cryst_const) assert st.get_cell() is not None np.testing.assert_almost_equal(crys.volume_cell(cell), crys.volume_cell(st.get_cell())) aaae(cryst_const, crys.cell2cc(st.get_cell())) # units st = Structure(coords_frac=coords_frac, cell=cell, symbols=symbols, stress=stress, forces=forces, units={'length': 2, 'forces': 3, 'stress': 4}) aaae(2*coords, st.coords) aaae(3*forces, st.forces) aaae(4*stress, st.stress) traj = crys.struct2traj(st) assert traj.is_traj # copy(): Assert everything has another memory location = is a new copy of # the object. IntTypes are NOT copied by copy.deepcopy(), which we use in # Structure.copy(), apparently b/c they are always automatically copied # before in-place operations. Same for float type. # # >>> a=10; b=a; print id(a); print id(b) # 36669152 # 36669152 # >>> a*=100; print id(a); print id(b) # 72538264 # 36669152 # >>> a # 100 # >>> b # 10 # # >>> a=[1,2,3]; b=a; print id(a); print id(b) # 72624320 # 72624320 # >>> a[0] = 44; print id(a); print id(b) # 72624320 # 72624320 # >>> a # [44, 2, 3] # >>> b # [44, 2, 3] st2 = st.copy() for name in st.attr_lst: val = getattr(st,name) if val is not None and not (isinstance(val, types.IntType) or \ isinstance(val, types.FloatType)): val2 = getattr(st2,name) assert id(val2) != id(val) assert_all_types_equal(val2, val)