...
 
Commits (35)
......@@ -115,3 +115,9 @@ venv.bak/
# mypy
.mypy_cache/
# macOS
.DS_Store
# Figures
*.png
image: registry.gitlab.com/compphys/qcad/tinie/dev:latest
image: registry.gitlab.com/compphys-public/tinie/dev:latest
stages:
- unittesting
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -4,7 +4,13 @@ source =
omit =
setup.py
.eggs/*
venv/*
tinie/main_routines/tests/*
tinie/systems/central_region/tests/*
tinie/systems/couplings/tests/*
tinie/systems/leads/tests/*
tinie/systems/read_write/tests/*
tinie/scripts/*
[report]
exclude_lines =
pragma: no cover
......
#!/bin/bash
BUILDPATH=(${PWD}/build/lib.*)
export PYTHONPATH=${PWD}:${BUILDPATH}:${PYTHONPATH}
#!/usr/bin/env python3
"""
Command line parser for calculating transmission and partial currents of a
coupling system.
"""
import argparse
import os
import sys
from shutil import move
import h5py
from mpi4py import MPI
from tinie.main_routines.calculator import Calculator
from tinie.main_routines.misc import *
# Importing the main system:
from tinie.systems.read_write.system_read import SystemRead
CWD = os.getcwd()
parser = argparse.ArgumentParser(description="""A script for calculating
transmission and partial currents through a
nanostructure connected to multiple leads. Check README.md for more details.""")
parser.add_argument('--delta-omega', '-dw', type=float, default=1e-2,
help="Probe energy grid spacing.")
parser.add_argument('-eta', type=float, default=1e-1,
help="Small imaginary constant eta.")
parser.add_argument('--chem-pot', '-mu', type=float, default=1.0,
help="Chemical potential in the system.")
parser.add_argument('--temperature', '-T', type=float, default=1.0,
help="Temperature of the system.")
parser.add_argument('--lead-bias', '-V', nargs='+', type=float,
default=[0.5, 1.5],
help="Bias voltages of the leads.")
parser.add_argument('--wide-band', dest='wide_band', action='store_true',
help="Use wide band approximation. Must provide own "
"self energy and rate operators.")
parser.add_argument('--no-wide-band', dest='wide_band', action='store_false',
help="Don't use wide band approximation (default).")
parser.add_argument('--self-energy', '-S', type=str, default="",
help="Path to the .npz file containing the self-energies"
" for the wide band approximation.")
parser.add_argument('--rate-operator', '-G', type=str, default="",
help="Path to the .npz file containing the rate operators "
"for the wide band approximation. If empty and self "
"energy is not, calculates the rate operators based "
"on the formula involving self energies.")
parser.add_argument('--input-file', '-i', type=str,
default=CWD + "/tinie_prepare.h5",
help="Input file to read coupling data from.")
parser.add_argument('--output-file', '-o', type=str,
default=CWD + "/tinie.h5",
help="Output file to write data to.")
parser.set_defaults(wide_band=False)
# Reading and checking the parameters:
args = parser.parse_args()
delta_w = args.delta_omega
eta = args.eta
chem_pot = args.chem_pot
T = args.temperature
V_bias = args.lead_bias
wide_band = args.wide_band
self_energy_path = args.self_energy
rate_operator_path = args.rate_operator
filepath_read = args.input_file
filepath_write = args.output_file
comm = MPI.COMM_WORLD
# Setting up the system:
if comm.rank == 0:
print("Initializing the transport calculator...")
system = SystemRead(comm)
system.set_file_path(filepath_read)
delta_E = system.get_lead_energy_spacing()
try:
if len(V_bias) != system.get_num_leads():
raise ValueError("Error: number of potentials inconsistent with the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
# Setting up the calculator:
calculator = Calculator(chem_pot, T, V_bias, system, delta_w, delta_E, eta,
comm, wide_band)
if wide_band:
try:
if self_energy_path == "" and rate_operator_path == "":
raise ValueError("Error: empty self energy and rate operator path, make sure to specify a "
"path for either self energies or rate operators if you are using "
"wide band approximation.")
except ValueError as e:
print(e)
sys.exit(1)
if self_energy_path != "" and rate_operator_path == "":
wide_band_self_energy = np.load(self_energy_path)
try:
if len(wide_band_self_energy) != system.get_num_leads(): \
raise ValueError("Error: number of self energy matrices not the "
"same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
wide_band_gamma = []
for i in range(system.get_num_leads()):
wide_band_gamma.append(1j * (wide_band_self_energy[i, :, :] -
np.conj(wide_band_self_energy[i, :, :].T)))
elif rate_operator_path != "" and self_energy_path == "":
wide_band_gamma = np.load(rate_operator_path)
try:
if len(wide_band_gamma) != system.get_num_leads():
raise ValueError("Error: number of rate operator matrices not "
"the same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
wide_band_self_energy = []
for i in range(system.get_num_leads()):
wide_band_self_energy.append(-0.5j * wide_band_gamma[i, :, :])
else:
wide_band_self_energy = np.load(self_energy_path)
wide_band_gamma = np.load(rate_operator_path)
try:
if len(wide_band_gamma) != system.get_num_leads() or \
len(wide_band_self_energy) != system.get_num_leads():
raise ValueError("Error: number of rate operator or self energy "
"matrices not the same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
calculator.set_wide_band_gamma(wide_band_gamma)
calculator.set_wide_band_self_energy(wide_band_self_energy)
comm.Barrier()
if comm.rank == 0:
print("Calculator is prepared, initializing coupling calculation...")
total_currents, total_currents_vs_energy, \
partial_currents, partial_currents_vs_energy, \
transmat_vs_energy, G_vs_energy, omega_values = calculator.currents()
comm.Barrier()
if comm.rank == 0:
print("Transport calculation complete, saving data...")
if os.path.exists(filepath_write):
old_filepath = filepath_write
new_filepath = filepath_write.rsplit('.', 1)[0] + "_backup." + \
filepath_write.rsplit('.', 1)[1]
print("File with same path detected, moving to " + new_filepath)
move(old_filepath, new_filepath)
# Setting up the hdf5 storage
file = h5py.File(filepath_write, 'w')
file.attrs["type"] = "TINIEFile"
file.create_dataset("partial_currents", data=np.real(partial_currents),
chunks=True, compression="gzip")
file.create_dataset("total_currents", data=np.real(total_currents),
chunks=True, compression="gzip")
file.create_dataset("omega_dependent_partial_currents",
data=np.real(partial_currents_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("omega_dependent_total_currents",
data=np.real(total_currents_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("transmission", data=np.real(transmat_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("transmission_error", data=np.imag(transmat_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("conductance", data=np.real(G_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("omega_values", data=omega_values,
chunks=True, compression="gzip")
file.attrs["evaluated_chemical_potential"] = chem_pot
file.attrs["evaluated_bias_voltage"] = V_bias
file.attrs["evaluated_temperature"] = T
file.attrs["omega_spacing"] = delta_w
file.attrs["lead_energy_spacing"] = delta_E
file.attrs["number_of_couplings"] = system.get_num_leads()
file.attrs["eta"] = eta
print("Transport data saved at " + filepath_write)
file.close()
comm.Barrier()
#!/usr/bin/env python3
"""
Command line parser for calculating DOS and LDOS of a coupling system.
"""
import argparse
import os
import sys
from shutil import move
import h5py
import tinie as tc
from mpi4py import MPI
from tinie.main_routines.calculator import Calculator
from tinie.main_routines.misc import *
from tinie.systems.central_region.itp2d_center import Itp2dCenter
# Importing the main system:
from tinie.systems.read_write.system_read import SystemRead
CWD = os.getcwd()
parser = argparse.ArgumentParser(description="""A script for calculating
density of states and local density of states through a
nanostructure connected to multiple leads. Check README.md for more
details.""")
parser.add_argument('--omega-ldos', '-w', nargs='+', type=float, default=[0.0, 1.0, 2.0],
help="Energies to evaluate LDOS at.")
parser.add_argument('--delta-omega', '-dw', type=float, default=1e-2,
help="Probe energy grid spacing.")
parser.add_argument('-eta', type=float, default=1e-1,
help="Small imaginary constant eta.")
parser.add_argument('--chem-pot', '-mu', type=float, default=1.0,
help="Chemical potential of the system.")
parser.add_argument('--temperature', '-T', type=float, default=1.0,
help="Temperature of the system.")
parser.add_argument('--lead-bias', '-V', nargs='+', type=float, default=[0.5, 1.5],
help="Bias voltages of the leads.")
parser.add_argument('--input-file', '-i', type=str,
default=CWD + "/tinie_prepare.h5",
help="Input file to read coupling data from.")
parser.add_argument('--wf-file', '-psi', type=str, default=tc.__path__[0] + "/test_files/itp2d_test.h5",
help="Path to the file that contains wavefunctions "
"required for LDOS computation.")
parser.add_argument('--wf-range', nargs=2, type=int, default=[0, 4],
help="Range of states to extract from the wavefunction "
"file required for LDOS.")
parser.add_argument('--output-file', '-o', type=str,
default=CWD + "/tinie_dos.h5",
help="Output file to write data to.")
parser.add_argument('--dos', dest='dos', action='store_true',
help="Evaluate DOS (default).")
parser.add_argument('--ldos', dest='ldos', action='store_true',
help="Evaluate LDOS (default).")
parser.add_argument('--no-dos', dest='dos', action='store_false',
help="Don't evaluate DOS.")
parser.add_argument('--no-ldos', dest='ldos', action='store_false',
help="Don't evaluate LDOS.")
parser.set_defaults(dos=True)
parser.set_defaults(ldos=True)
# Reading and checking the parameters:
args = parser.parse_args()
w = np.array(args.omega_ldos)
delta_w = args.delta_omega
eta = args.eta
eval_dos = args.dos
eval_ldos = args.ldos
chem_pot = args.chem_pot
T = args.temperature
V_bias = args.lead_bias
filepath_read = args.input_file
filepath_dos_write = args.output_file
filepath_wf = args.wf_file
wf_range = args.wf_range
comm = MPI.COMM_WORLD
# Setting up the system:
if comm.rank == 0:
print("Initializing the transport calculator...")
system = SystemRead(comm)
system.set_file_path(filepath_read)
delta_E = system.get_lead_energy_spacing()
try:
if system.get_center_type() != "Itp2dCenter":
raise ValueError("Error: currently, only Itp2dCenter center objects are LDOS compatible.")
if comm.size != 1 and eval_ldos:
raise ValueError("Error: currently, LDOS is not parallelised.")
if len(V_bias) != system.get_num_leads():
raise ValueError("Error: number of potentials inconsistent with the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
# Setting up the calculator:
calculator = Calculator(chem_pot, T, V_bias, system, delta_w, delta_E, eta,
comm, False)
comm.Barrier()
if comm.rank == 0:
print("Calculator is prepared, initializing DOS/LDOS calculation...")
omega_values = calculator.get_omega_range()
if eval_dos:
dos_values = calculator.get_dos()
else:
dos_values = np.array([])
if eval_ldos:
if comm.rank == 0:
ctr = Itp2dCenter(filepath_wf, tuple(wf_range))
psi = ctr.get_states()
x, y = ctr.get_coordinate_ranges()
x_size = len(x)
y_size = len(y)
num_states = wf_range[1] - wf_range[0] + 1
else:
x_size = None
y_size = None
num_states = None
x_size = comm.bcast(x_size, root=0)
y_size = comm.bcast(y_size, root=0)
num_states = comm.bcast(num_states, root=0)
comm.Barrier()
if comm.rank != 0:
psi = np.zeros((x_size, y_size, num_states), dtype=np.complex128)
comm.Bcast(psi, root=0)
comm.Bcast(x, root=0)
comm.Bcast(y, root=0)
comm.Barrier()
ldos_values_partial = calculator.get_ldos(psi, w)
ldos_values = np.zeros(ldos_values_partial.shape)
comm.Reduce(ldos_values_partial, ldos_values, MPI.SUM, 0)
else:
x = np.array([])
y = np.array([])
ldos_values = np.array([])
comm.Barrier()
if comm.rank == 0:
print("DOS/LDOS calculation complete, saving data...")
if os.path.exists(filepath_dos_write):
old_filepath = filepath_dos_write
new_filepath = filepath_dos_write.rsplit('.', 1)[0] + "_backup." + \
filepath_dos_write.rsplit('.', 1)[1]
print("File with same path detected, moving to " + new_filepath)
move(old_filepath, new_filepath)
# Setting up the hdf5 storage
file = h5py.File(filepath_dos_write, 'w')
file.attrs["type"] = "TINIEDOSFile"
file.create_dataset("dos", data=dos_values,
chunks=True, compression="gzip")
file.create_dataset("ldos", data=ldos_values,
chunks=True, compression="gzip")
file.create_dataset("x", data=x,
chunks=True, compression="gzip")
file.create_dataset("y", data=y,
chunks=True, compression="gzip")
file.create_dataset("omega_dos", data=omega_values,
chunks=True, compression="gzip")
file.create_dataset("omega_ldos", data=w, chunks=True,
compression="gzip")
print("DOS/LDOS data saved at " + filepath_dos_write)
file.close()
comm.Barrier()
This diff is collapsed.
#!/usr/bin/env python3
"""
Command line parser for calculating coupling and hamiltonians of a transport
system.
"""
import argparse
import os
import sys
import tinie as tc
from mpi4py import MPI
from tinie.main_routines.misc import *
from tinie.systems.central_region.custom_center import CustomCenter
# Importing the center region types:
from tinie.systems.central_region.itp2d_center import Itp2dCenter
from tinie.systems.couplings.custom_coupling import CustomCoupling
from tinie.systems.couplings.one_layer_coupling import OneLayerCoupling
# Importing the coupling region types:
from tinie.systems.couplings.overlap_coupling import OverlapCoupling
from tinie.systems.couplings.tight_binding_coupling import TightBindingCoupling
from tinie.systems.leads.box_lead import BoxLead
from tinie.systems.leads.custom_lead import CustomLead
# Importing the lead region types:
from tinie.systems.leads.finite_harmonic_lead import FiniteHarmonicLead
# Importing the main system:
from tinie.systems.read_write.system_write import SystemWrite
CWD = os.getcwd()
ctr = {'itp2d': Itp2dCenter,
'custom': CustomCenter}
ld = {'finharm': FiniteHarmonicLead,
'box': BoxLead,
'custom': CustomLead}
cpl = {'overlap': OverlapCoupling,
'tightbind': TightBindingCoupling,
'onelayer': OneLayerCoupling,
'custom': CustomCoupling}
parser = argparse.ArgumentParser(description="""A script for calculating
Hamiltonains and couplings of a transport system. Check README.md for more
details.""")
parser.add_argument('--delta-E', '-dE', type=float, default=1e-3,
help="Lead region energy grid spacing.")
parser.add_argument('-B', type=float, default=0.0,
help="Magnetic field strength.")
parser.add_argument('--x-axis-limits', '-xlim', nargs='+',
type=str, default=["[-10.0, -4.0]", "[4.0, 10.0]"],
help="Lead x-axis boundaries, specified as pairs of "
"floats of the form '[xmin, xmax]'.")
parser.add_argument('--y-axis-limits', '-ylim', nargs='+',
type=str, default=["[-5.0, 5.0]", "[-5.0, 5.0]"],
help="Lead y-axis boundaries, specified as pairs of "
"floats of the form '[ymin, ymax]'.")
parser.add_argument('--energy-limits', '-Elim', nargs='+',
type=str, default=["[0.0, 2.0]", "[0.0, 2.0]"],
help="Lead energy boundaries, specified as pairs of "
"floats of the form '[Emin, Emax]'.")
parser.add_argument('--center-type', '-ctr', type=str,
default="itp2d(" + tc.__path__[0] +
"/test_files/itp2d_test.h5,(0,4))",
help="""Central region type, takes a string as input and
currently supports the following: (1)
'itp2d(FILENAME,STATES)': import of the central region
states from itp2d software package, FILENAME is the full
path to the itp2d .h5 file, and STATES is a pair of
integers of form (state_init, state_fin) that defines the
range of states to be imported. (2) 'custom(FILENAME)':
import of the custom central region Hamiltonian, FILENAME
is the full path to a .npy file containing the Hamiltonian
array. Check README.md for more details.""")
parser.add_argument('--lead-number', '-l', type=int, default=2,
help="Number of leads in the simulation.")
parser.add_argument('--lead-types', '-ld', nargs='+', type=str,
default=["finharm(left, 1.0, dir)",
"finharm(right, 1.0, dir)"],
help="""Types of leads in the simulation, with their
additional arguments, typed as a sequence of strings
corresponding to the lead types.
Currently supports the following:
(1) 'finharm(ALIGNMENT,W0,BOUNDARY)': finite harmonic
lead with particle-in-a-box potential in one
dimension and harmonic oscillator potential of
frequency W0 in the other, with ALIGNMENT
corresponding to position of the lead in relation
to the central region (up/down/left/right), and
BOUNDARY (dir/neu) corresponding to
Dirichlet/Neumann boundary conditions used for the
eigenfunctions. (2) 'box(ALIGNMENT)': lead that is
confined with a particle-in-a-box potential in
both x- and y-dimensions, with ALIGNMENT parameter
similar to that of finharm. (3) 'custom(FILENAME)':
custom lead Hamiltonian imported from the .npy
file located at FILENAME. Check README.md for more
details.""")
parser.add_argument('--coupling-types', '-cpl', nargs='+', type=str,
default=["overlap()", "overlap()"],
help="""Types of the coupling regions for the leads. Typed
as a sequence of strings corresponding to the overlap type
between each lead and the center. The following are currently
supported: (1) 'overlap()': coupling based on computing the
overlap integral between the lead and the central region,
so they must spatially overlap. (2) 'tightbind()':
calculates coupling using the tight binding method, for
which the lead and center regions must not overlap.
(3) 'onelayer()': version of the tight binding coupling
method optimised for computing coupling between two 1D
layers of the lead and central region, which must not
overlap. (4) 'custom(FILENAME)': import custom coupling
matrix from a .npy file located at FILENAME. Check
README.md for more details.""")
parser.add_argument('--output-file', '-o', type=str,
default=CWD + '/tinie_prepare.h5',
help="Output file to write data to.")
# Reading and checking the parameters:
args = parser.parse_args()
ld_num = args.lead_number
delta_E = args.delta_E
B = args.B
xlims = []
for arg in args.x_axis_limits:
xlims.append(handle_list_string(arg))
ylims = []
for arg in args.y_axis_limits:
ylims.append(handle_list_string(arg))
Elims = []
for arg in args.energy_limits:
Elims.append(handle_list_string(arg))
ctr_args = handle_function_string(args.center_type)
ld_args = args.lead_types
cpl_args = args.coupling_types
# Some input sanity checks:
try:
if len(xlims) != ld_num:
raise ValueError("Error: number of x-axis boundaries inconsistent with number of leads.")
if len(ylims) != ld_num:
raise ValueError("Error: number of y-axis boundaries inconsistent with number of leads.")
if len(Elims) != ld_num:
raise ValueError("Error: number of energy boundaries inconsistent with number of leads.")
if ld_num == False:
raise ValueError("Error: invalid number of leads, only integer values!")
if len(ld_args) != ld_num:
raise ValueError("Error: lead parameters inconsistent with number of leads.")
if ld_num != len(cpl_args):
raise ValueError("Error: number of coupling regions inconsistent with number of lead regions.")
if ctr_args[0] not in ctr.keys():
raise ValueError("Error: invalid central region type.")
except ValueError as e:
print(e)
sys.exit(1)
filename_write = args.output_file
# Setting up the communicator:
comm = MPI.COMM_WORLD
# Setting up the system:
if comm.rank == 0:
print("Initializaing the coupling system...")
system = SystemWrite(comm)
system.set_file_path(filename_write)
center = ctr[ctr_args[0]](*ctr_args[1:])
system.add_central_region(center)
comm.Barrier()
for i in range(ld_num):
ld_params = handle_function_string(ld_args[i])
cpl_params = handle_function_string(cpl_args[i])
try:
if ld_params[0] not in ld.keys():
raise ValueError("Error: invalid Lead %s region type." % i)
if cpl_params[0] not in cpl.keys():
raise ValueError("Error: invalid Coupling %s region type." % i)
except ValueError as e:
print(e)
sys.exit(1)
lead = ld[ld_params[0]](xlims[i], ylims[i], Elims[i], delta_E,
*ld_params[1:])
lead.set_magnetic_field_strength(B)
coupling = cpl[cpl_params[0]](center, lead, *cpl_params[1:], comm)
system.add_coupling_region(coupling)
comm.Barrier()
if comm.rank == 0:
print("System prepared, initializing coupling calculation...")
system.dump()
comm.Barrier()
if comm.rank == 0:
print("Coupling calculation complete, data saved at " + filename_write)
......@@ -17,10 +17,17 @@ setup(name='tinie',
'Operating System :: POSIX'
],
description='A non-interacting equilibrium 2D quantum transport simulation framework',
long_description=open("README.md",'r').read(),
long_description_content_type='text/markdown',
scripts=['scripts/tinie_prepare', 'scripts/tinie','scripts/tinie_dos',
'scripts/tinie_draw', 'scripts/make_system_files'],
entry_points={
'console_scripts': [
'make_system_files = tinie.scripts.make_system_files:user_interface',
'tinie = tinie.scripts.tinie:main',
'tinie_dos = tinie.scripts.tinie_dos:main',
'tinie_draw = tinie.scripts.tinie_draw:main',
'tinie_prepare = tinie.scripts.tinie_prepare:main'
]
},
long_description=open("README.rst",'r').read(),
long_description_content_type='text/x-rst',
install_requires=['numpy', 'scipy', 'mpi4py', 'progressbar2', 'findiff',
'matplotlib', 'h5py', 'vegas'],
keywords='numerics quantum transport physics',
......@@ -30,7 +37,7 @@ setup(name='tinie',
python_requires='>=3.6',
test_suite='nose2.collector.collector',
tests_require=['nose2'],
url='https://gitlab.com/compphys/qcad/tinie',
url='https://gitlab.com/compphys-public/tinie',
version=my_pkg.__version__,
zip_safe=False
)
......@@ -7,8 +7,6 @@ __author__ = "Rostislav Duda, Joonas Keski-Rahkonen, Janne Solanpää"
__copyright__ = ("Copyright 2019-2020, Rostislav Duda, Joonas Keski-Rahkonen & Janne Solanpää")
__author_email__ = "[email protected]"
__license__ = "Boost Software License 1.0"
__version__ = "1.0.1"
__version__ = "1.0.3"
from tinie.main_routines.calculator import Calculator
import warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# Byte-compiled / optimized / DLL files
__pycache__/
.idea/
*.py[cod]
*$py.class
# HDF5
*.h5
*.pdf
# C++ extensions
*.o
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# Byte-compiled / optimized / DLL files
__pycache__/
.idea/
*.py[cod]
*$py.class
# HDF5
*.h5
*.pdf
# C++ extensions
*.o
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
......@@ -2,39 +2,127 @@
"""
A script for generating custom system couplings/hamiltonians.
"""
from typing import List, Text
import numpy as np
def ask_int(query: Text) -> int:
"""
Parameters
----------
query : Text
Query-string
Returns
-------
int
"""
while True:
try:
return int(input(f"{query}: ").strip())
except ValueError:
print("Could not interpret the input as an integer.")
def ask_float_array(query: Text, expected_length: int) -> List[float]:
"""
Parameters
----------
query : Text
Query-string
expected_length : int
Expected length of the array
Returns
-------
List[float]
"""
while True:
try:
user_input = input(f"{query}: ").strip()
numbers = user_input.split(' ')
if len(numbers) != expected_length:
raise ValueError("Length of the input array not what was expected: {len(numbers)} vs {"
"expected_length}")
return [float(num) for num in numbers]
except ValueError as e:
print(e)
def ask_complex_array(query: Text, expected_length: int) -> List[np.complex]:
"""
Parameters
----------
query : Text
Query-string
expected_length : int
Expected length of the array
Returns
-------
List[float]
"""
while True:
try:
user_input = input(f"{query}: ").strip()
numbers = user_input.split(' ')
if len(numbers) != expected_length:
raise ValueError("Length of the input array not what was expected: {len(numbers)} vs {"
"expected_length}")
return [np.complex(c) for c in numbers]
except ValueError as e:
print(e)
def ask_complex_matrix(query: Text, expected_rowsize: int, expected_columnsize: int) -> np.ndarray:
"""
Parameters
----------
query :
expected_rowsize :
expected_columnsize :
Returns
-------
"""
mat = np.empty((expected_rowsize, expected_columnsize), dtype=np.complex)
for i in range(expected_rowsize):
mat[i,:] = ask_complex_array(f"row {i}", expected_columnsize)
return mat
def generate_custom_hamiltonian():
"""
Generates a custom Hamiltonian and stores it in a .npy file.
"""
state_num = int(input("Enter the number of eigenenergies: "))
state_num = ask_int("Enter the number of eigenenergies")
hamiltonian = np.empty((state_num,), dtype=float)
hamiltonian = np.zeros((state_num,), dtype=float)
filename_default = "custom_hamiltonian"
E_vals = input("Enter the eigenenenergy values separated by spaces: ")
filename_default = "data/custom_hamiltonian"
E_vals = E_vals.split()
assert len(E_vals) == state_num, \
"Number of eigenenergies inconsistent with the one specified"
hamiltonian[:] = [float(val) for val in E_vals]
hamiltonian[:] = ask_float_array("Enter the eigenenenergy values separated by spaces", expected_length=state_num)
print("Hamiltonian imported")
filename = input(
"Now specify the file name, default is " + filename_default + ": ")
"Now specify the output file name, default is " + filename_default + ": ")
if filename == "":
np.save("data/" + filename_default, hamiltonian)
np.save(filename_default, hamiltonian)
print(
"Hamiltonian successfully saved at data/" +
"Hamiltonian successfully saved at " +
filename_default + ".npy")
else:
np.save("data/" + filename, hamiltonian)
print("Hamiltonian successfully saved at data/" + filename + ".npy")
np.save(filename, hamiltonian)
print("Hamiltonian successfully saved at " + filename + ".npy")
def generate_custom_coupling():
......@@ -42,49 +130,31 @@ def generate_custom_coupling():
Generates a custom coupling matrix and stores it in a .npy file.
"""
state_num_ld = int(input("Enter number of states in the lead: "))
state_num_ctr = int(input("Enter number of states in the "
"central region: "))
state_num_ld = ask_int("Enter number of states in the lead")
state_num_ctr = ask_int("Enter number of states in the central region")
cpl_matrix = np.zeros((state_num_ld, state_num_ctr), dtype=np.complex128)
filename_default = "custom_coupling"
filename_default = "data/custom_coupling"
print("Here is a little tutorial:")
print("Enter your matrix in the form [x11 x12 x13 ; x21 x22 x23 ; "
"x31 x32 x33]")
print("Enter your matrix row-by-row space separated.")
print("Complex values are allowed and can be typed in as e.g. "
"1.+1.j, j is the complex unit")
cpl_vals = input("Now enter the coupling matrix: ")
assert cpl_vals[0] == "["
assert cpl_vals[-1] == "]"
cpl_vals = cpl_vals.lstrip("[")
cpl_vals = cpl_vals.rstrip("]")
cpl_rows = cpl_vals.split(";")
assert len(cpl_rows) == state_num_ld, \
"Number of rows inconsistent with number of lead states"
for i, row in enumerate(cpl_rows):
row_values = [complex(val) for val in row.split()]
assert len(row_values) == state_num_ctr, \
"Number of items in one row inconsistent " \
"with number of center states"
cpl_matrix[i, :] = row_values
cpl_matrix = ask_complex_matrix("Input coupling matrix row-by-row", state_num_ld, state_num_ctr)
print("Matrix imported")
filename = input(
"Now specify the file name, default is " + filename_default + ": ")
if filename == "":
np.save("data/" + filename_default, cpl_matrix)
print("Coupling matrix successfully saved at data/" +
np.save(filename_default, cpl_matrix)
print("Coupling matrix successfully saved at " +
filename_default + ".npy")
else:
np.save("data/" + filename, cpl_matrix)
print("Coupling matrix successfully saved at data/" +
np.save(filename, cpl_matrix)
print("Coupling matrix successfully saved at " +
filename + ".npy")
......@@ -116,4 +186,5 @@ def user_interface():
print("and 'q' to quit.")
user_interface()
if __name__ == '__main__':
user_interface()
\ No newline at end of file
#!/usr/bin/env python3
"""
Command line parser for calculating transmission and partial currents of a
coupling system.
"""
import argparse
import os
import sys
from shutil import move
import h5py
from mpi4py import MPI
from tinie.main_routines.calculator import Calculator
from tinie.main_routines.misc import *
# Importing the main system:
from tinie.systems.read_write.system_read import SystemRead
def main():
CWD = os.getcwd()
parser = argparse.ArgumentParser(description="""A script for calculating
transmission and partial currents through a
nanostructure connected to multiple leads. Check README.md for more details.""")
parser.add_argument('--delta-omega', '-dw', type=float, default=1e-2,
help="Probe energy grid spacing.")
parser.add_argument('-eta', type=float, default=1e-1,
help="Small imaginary constant eta.")
parser.add_argument('--chem-pot', '-mu', type=float, default=1.0,
help="Chemical potential in the system.")
parser.add_argument('--temperature', '-T', type=float, default=1.0,
help="Temperature of the system.")
parser.add_argument('--lead-bias', '-V', nargs='+', type=float,
default=[0.5, 1.5],
help="Bias voltages of the leads.")
parser.add_argument('--wide-band', dest='wide_band', action='store_true',
help="Use wide band approximation. Must provide own "
"self energy and rate operators.")
parser.add_argument('--no-wide-band', dest='wide_band', action='store_false',
help="Don't use wide band approximation (default).")
parser.add_argument('--self-energy', '-S', type=str, default="",
help="Path to the .npz file containing the self-energies"
" for the wide band approximation.")
parser.add_argument('--rate-operator', '-G', type=str, default="",
help="Path to the .npz file containing the rate operators "
"for the wide band approximation. If empty and self "
"energy is not, calculates the rate operators based "
"on the formula involving self energies.")
parser.add_argument('--input-file', '-i', type=str,
default=CWD + "/tinie_prepare.h5",
help="Input file to read coupling data from.")
parser.add_argument('--output-file', '-o', type=str,
default=CWD + "/tinie.h5",
help="Output file to write data to.")
parser.set_defaults(wide_band=False)
# Reading and checking the parameters:
args = parser.parse_args()
delta_w = args.delta_omega
eta = args.eta
chem_pot = args.chem_pot
T = args.temperature
V_bias = args.lead_bias
wide_band = args.wide_band
self_energy_path = args.self_energy
rate_operator_path = args.rate_operator
filepath_read = args.input_file
filepath_write = args.output_file
comm = MPI.COMM_WORLD
# Setting up the system:
if comm.rank == 0:
print("Initializing the transport calculator...")
system = SystemRead(comm)
system.set_file_path(filepath_read)
delta_E = system.get_lead_energy_spacing()
try:
if len(V_bias) != system.get_num_leads():
raise ValueError("Error: number of potentials inconsistent with the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
# Setting up the calculator:
calculator = Calculator(chem_pot, T, V_bias, system, delta_w, delta_E, eta,
comm, wide_band)
if wide_band:
try:
if self_energy_path == "" and rate_operator_path == "":
raise ValueError("Error: empty self energy and rate operator path, make sure to specify a "
"path for either self energies or rate operators if you are using "
"wide band approximation.")
except ValueError as e:
print(e)
sys.exit(1)
if self_energy_path != "" and rate_operator_path == "":
wide_band_self_energy = np.load(self_energy_path)
try:
if len(wide_band_self_energy) != system.get_num_leads(): \
raise ValueError("Error: number of self energy matrices not the "
"same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
wide_band_gamma = []
for i in range(system.get_num_leads()):
wide_band_gamma.append(1j * (wide_band_self_energy[i, :, :] -
np.conj(wide_band_self_energy[i, :, :].T)))
elif rate_operator_path != "" and self_energy_path == "":
wide_band_gamma = np.load(rate_operator_path)
try:
if len(wide_band_gamma) != system.get_num_leads():
raise ValueError("Error: number of rate operator matrices not "
"the same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
wide_band_self_energy = []
for i in range(system.get_num_leads()):
wide_band_self_energy.append(-0.5j * wide_band_gamma[i, :, :])
else:
wide_band_self_energy = np.load(self_energy_path)
wide_band_gamma = np.load(rate_operator_path)
try:
if len(wide_band_gamma) != system.get_num_leads() or \
len(wide_band_self_energy) != system.get_num_leads():
raise ValueError("Error: number of rate operator or self energy "
"matrices not the same as the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
calculator.set_wide_band_gamma(wide_band_gamma)
calculator.set_wide_band_self_energy(wide_band_self_energy)
comm.Barrier()
if comm.rank == 0:
print("Calculator is prepared, initializing coupling calculation...")
total_currents, total_currents_vs_energy, \
partial_currents, partial_currents_vs_energy, \
transmat_vs_energy, G_vs_energy, omega_values = calculator.currents()
comm.Barrier()
if comm.rank == 0:
print("Transport calculation complete, saving data...")
if os.path.exists(filepath_write):
old_filepath = filepath_write
new_filepath = filepath_write.rsplit('.', 1)[0] + "_backup." + \
filepath_write.rsplit('.', 1)[1]
print("File with same path detected, moving to " + new_filepath)
move(old_filepath, new_filepath)
# Setting up the hdf5 storage
file = h5py.File(filepath_write, 'w')
file.attrs["type"] = "TINIEFile"
file.create_dataset("partial_currents", data=np.real(partial_currents),
chunks=True, compression="gzip")
file.create_dataset("total_currents", data=np.real(total_currents),
chunks=True, compression="gzip")
file.create_dataset("omega_dependent_partial_currents",
data=np.real(partial_currents_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("omega_dependent_total_currents",
data=np.real(total_currents_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("transmission", data=np.real(transmat_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("transmission_error", data=np.imag(transmat_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("conductance", data=np.real(G_vs_energy),
chunks=True, compression="gzip")
file.create_dataset("omega_values", data=omega_values,
chunks=True, compression="gzip")
file.attrs["evaluated_chemical_potential"] = chem_pot
file.attrs["evaluated_bias_voltage"] = V_bias
file.attrs["evaluated_temperature"] = T
file.attrs["omega_spacing"] = delta_w
file.attrs["lead_energy_spacing"] = delta_E
file.attrs["number_of_couplings"] = system.get_num_leads()
file.attrs["eta"] = eta
print("Transport data saved at " + filepath_write)
file.close()
comm.Barrier()
if __name__ == '__main__':
main()
\ No newline at end of file
#!/usr/bin/env python3
"""
Command line parser for calculating DOS and LDOS of a coupling system.
"""
import argparse
import os
import sys
from shutil import move
import h5py
import tinie as tc
from mpi4py import MPI
from tinie.main_routines.calculator import Calculator
from tinie.main_routines.misc import *
from tinie.systems.central_region.itp2d_center import Itp2dCenter
# Importing the main system:
from tinie.systems.read_write.system_read import SystemRead
def main():
CWD = os.getcwd()
parser = argparse.ArgumentParser(description="""A script for calculating
density of states and local density of states through a
nanostructure connected to multiple leads. Check README.md for more
details.""")
parser.add_argument('--omega-ldos', '-w', nargs='+', type=float, default=[0.0, 1.0, 2.0],
help="Energies to evaluate LDOS at.")
parser.add_argument('--delta-omega', '-dw', type=float, default=1e-2,
help="Probe energy grid spacing.")
parser.add_argument('-eta', type=float, default=1e-1,
help="Small imaginary constant eta.")
parser.add_argument('--chem-pot', '-mu', type=float, default=1.0,
help="Chemical potential of the system.")
parser.add_argument('--temperature', '-T', type=float, default=1.0,
help="Temperature of the system.")
parser.add_argument('--lead-bias', '-V', nargs='+', type=float, default=[0.5, 1.5],
help="Bias voltages of the leads.")
parser.add_argument('--input-file', '-i', type=str,
default=CWD + "/tinie_prepare.h5",
help="Input file to read coupling data from.")
parser.add_argument('--wf-file', '-psi', type=str, default=tc.__path__[0] + "/test_files/itp2d_test.h5",
help="Path to the file that contains wavefunctions "
"required for LDOS computation.")
parser.add_argument('--wf-range', nargs=2, type=int, default=[0, 4],
help="Range of states to extract from the wavefunction "
"file required for LDOS.")
parser.add_argument('--output-file', '-o', type=str,
default=CWD + "/tinie_dos.h5",
help="Output file to write data to.")
parser.add_argument('--dos', dest='dos', action='store_true',
help="Evaluate DOS (default).")
parser.add_argument('--ldos', dest='ldos', action='store_true',
help="Evaluate LDOS (default).")
parser.add_argument('--no-dos', dest='dos', action='store_false',
help="Don't evaluate DOS.")
parser.add_argument('--no-ldos', dest='ldos', action='store_false',
help="Don't evaluate LDOS.")
parser.set_defaults(dos=True)
parser.set_defaults(ldos=True)
# Reading and checking the parameters:
args = parser.parse_args()
w = np.array(args.omega_ldos)
delta_w = args.delta_omega
eta = args.eta
eval_dos = args.dos
eval_ldos = args.ldos
chem_pot = args.chem_pot
T = args.temperature
V_bias = args.lead_bias
filepath_read = args.input_file
filepath_dos_write = args.output_file
filepath_wf = args.wf_file
wf_range = args.wf_range
comm = MPI.COMM_WORLD
# Setting up the system:
if comm.rank == 0:
print("Initializing the transport calculator...")
system = SystemRead(comm)
system.set_file_path(filepath_read)
delta_E = system.get_lead_energy_spacing()
try:
if system.get_center_type() != "Itp2dCenter":
raise ValueError("Error: currently, only Itp2dCenter center objects are LDOS compatible.")
if comm.size != 1 and eval_ldos:
raise ValueError("Error: currently, LDOS is not parallelised.")
if len(V_bias) != system.get_num_leads():
raise ValueError("Error: number of potentials inconsistent with the number of leads.")
except ValueError as e:
print(e)
sys.exit(1)
# Setting up the calculator:
calculator = Calculator(chem_pot, T, V_bias, system, delta_w, delta_E, eta,
comm, False)
comm.Barrier()
if comm.rank == 0:
print("Calculator is prepared, initializing DOS/LDOS calculation...")
omega_values = calculator.get_omega_range()
if eval_dos: