def sp2HS(cls, geom, H, S=None): """ Returns a tight-binding model from a preset H, S and Geometry """ # Calculate number of connections nc = 0 has_S = not S is None # Ensure csr format H = H.tocsr() if has_S: S = S.tocsr() for i in range(geom.no): nc = max(nc, H[i, :].getnnz()) if has_S: nc = max(nc, S[i, :].getnnz()) # Create the Hamiltonian ham = cls(geom, nnzpr=nc, orthogonal=not has_S, dtype=H.dtype) # Copy data to the model if has_S: for jo, io in ispmatrix(H): ham.S[jo, io] = S[jo, io] # If the Hamiltonian for one reason or the other # is zero in the diagonal, then we *must* account for # this as it isn't captured in the above loop. skip_S = np.all(H.row == S.row) skip_S = skip_S and np.all(H.col == S.col) skip_S = False if not skip_S: # Re-convert back to allow index retrieval H = H.tocsr() for jo, io, s in ispmatrixd(S): ham[jo, io] = (H[jo, io], s) else: for jo, io, h in ispmatrixd(H): ham[jo, io] = h return ham
def write_hamiltonian(self, ham, hermitian=True, **kwargs): """ Writes the Hamiltonian model to the file Writes a Hamiltonian model to the intrinsic Hamiltonian file format. The file can be constructed by the implict force of Hermiticity, or without. Utilizing the Hermiticity we reduce the file-size by approximately 50%. Parameters ---------- ham : `Hamiltonian` model hermitian : boolean=True whether the stored data is halved using the Hermitian property """ ham.finalize() # We use the upper-triangular form of the Hamiltonian # and the overlap matrix for hermitian problems geom = ham.geometry # First write the geometry self.write_geometry(geom, **kwargs) # We default to the advanced layuot if we have more than one # orbital on any one atom advanced = kwargs.get( 'advanced', np.any(np.array([a.no for a in geom.atom.atom], np.int32) > 1)) fmt = kwargs.get('fmt', 'g') if advanced: fmt1_str = ' {{0:d}}[{{1:d}}] {{2:d}}[{{3:d}}] {{4:{0}}}\n'.format( fmt) fmt2_str = ' {{0:d}}[{{1:d}}] {{2:d}}[{{3:d}}] {{4:{0}}} {{5:{0}}}\n'.format( fmt) else: fmt1_str = ' {{0:d}} {{1:d}} {{2:{0}}}\n'.format(fmt) fmt2_str = ' {{0:d}} {{1:d}} {{2:{0}}} {{3:{0}}}\n'.format(fmt) # We currently force the model to be finalized # before we can write it # This should be easily circumvented H = ham.tocsr(0) if not ham.orthogonal: S = ham.tocsr(ham.S_idx) # If the model is Hermitian we can # do with writing out half the entries if hermitian: herm_acc = kwargs.get('herm_acc', 1e-6) # We check whether it is Hermitian (not S) for i, isc in enumerate(geom.sc.sc_off): oi = i * geom.no oj = geom.sc_index(-isc) * geom.no # get the difference between the ^\dagger elements diff = H[:, oi:oi + geom.no] - \ H[:, oj:oj + geom.no].transpose() diff.eliminate_zeros() if np.any(np.abs(diff.data) > herm_acc): amax = np.amax(np.abs(diff.data)) warn( SileWarning( 'The model could not be asserted to be Hermitian ' 'within the accuracy required ({0}).'.format( amax))) hermitian = False del diff if hermitian: # Remove all double stuff for i, isc in enumerate(geom.sc.sc_off): if np.any(isc < 0): # We have ^\dagger element, remove it o = i * geom.no # Ensure that we remove all nullified quantities # (setting elements to zero will add them internally # :(, hence this actually constructs the full matrix # Therefore we do it on a row basis, to limit memory # requirements for j in range(geom.no): H[j, o:o + geom.no] = 0. H.eliminate_zeros() if not ham.orthogonal: S[j, o:o + geom.no] = 0. S.eliminate_zeros() o = geom.sc_index(np.zeros([3], np.int32)) # Get upper-triangular matrix of the unit-cell H and S ut = triu(H[:, o:o + geom.no], k=0).tocsr() for j in range(geom.no): H[j, o:o + geom.no] = 0. H[j, o:o + geom.no] = ut[j, :] H.eliminate_zeros() if not ham.orthogonal: ut = triu(S[:, o:o + geom.no], k=0).tocsr() for j in range(geom.no): S[j, o:o + geom.no] = 0. S[j, o:o + geom.no] = ut[j, :] S.eliminate_zeros() # Ensure that S and H have the same sparsity pattern for jo, io in ispmatrix(S): H[jo, io] = H[jo, io] del ut # Start writing of the model # We loop on all super-cells for i, isc in enumerate(geom.sc.sc_off): # Check that we have any contributions in this # sub-section Hsub = H[:, i * geom.no:(i + 1) * geom.no] if not ham.orthogonal: Ssub = S[:, i * geom.no:(i + 1) * geom.no] if Hsub.getnnz() == 0: continue # We have a contribution, write out the information self._write('\nbegin matrix {0:d} {1:d} {2:d}\n'.format(*isc)) if advanced: for jo, io, h in ispmatrixd(Hsub): o = np.array([jo, io], np.int32) a = geom.o2a(o) o = o - geom.a2o(a) if not ham.orthogonal: s = Ssub[jo, io] elif jo == io: s = 1. else: s = 0. if s == 0.: self._write(fmt1_str.format(a[0], o[0], a[1], o[1], h)) else: self._write( fmt2_str.format(a[0], o[0], a[1], o[1], h, s)) else: for jo, io, h in ispmatrixd(Hsub): if not ham.orthogonal: s = Ssub[jo, io] elif jo == io: s = 1. else: s = 0. if s == 0.: self._write(fmt1_str.format(jo, io, h)) else: self._write(fmt2_str.format(jo, io, h, s)) self._write('end matrix {0:d} {1:d} {2:d}\n'.format(*isc))