Reputation: 21
TLDR : How can I generate an array whose elements depend on some arbitrary (float) value, k, without having to go through the extremely time-expensive process of constructing the array from scratch every time I change the value of k.
What I want to achieve would look like:
I am generating a huge Hamiltonian in the atomic basis of a 2D lattice (N x N numpy array). Filling this array requires comparing positions (xyz) of the atomic sites multiple times for each different coupling types that I want to include, becoming very time-expensive as the system size grows. (typically N > 16,000 sites).
Elements of this array have a dependence upon some other float type variable, k (in the physical context of the program this is a quantum counting number that I want to iterate over). I need to calculate this array many times for a range of 1000 k-values.
i.e generate the 256,000,000 element array 1000 times... eurgh
At present I have to create the array every time I change to a new k-value which is obviously very inefficient. The basic structure of this looks (very generally) like:
class Device():
def __init__(self, xyz, energy, ... other input parameters ...):
self.xyz = xyz # N x 3 array of positions
self.energy = energy # Length N list of energies
# + A range of other parameters that define the device
# -------- OTHER OPERATIONS ON THE DEVICE -------- #
def get_H(self, k):
""" Get the Hamiltonian for a given k - value """
# Initialise the N x N array
h = np.zeros((len(self.xyz), len(self.xyz)))
# - Fill THE HAMILTONIAN BY COMPARING ALL ATOMIC POSITIONS IN self.xyz - #
return h
which requires that I call the entire construction process each time.
I want to know if there is a way to generate this array once, with k having been left as a free parameter which can then be filled in later. i.e return an array which is a function of k. The priority is to only have to construct the array once since testing indicates that this takes a significant portion of my total run-time.
Below is a minimal (non-working) example of what I want to achieve by acting on a test array. I want to make the Hamiltonian an object variable rather than a method that has to be made each time, but with some dependence on k (I realise that this will be syntactically disastrous but hopefully will be a good start for an answer).
class Test_device():
def __init__():
self.get_H = self.make_H()
def make_H(self):
h = np.linspace(1,9,9).reshape((3,3)) # Test array
# The below clearly will not work because k is not defined, but this is
# where I want to achieve this
h[1,1] += k # Give some k-dependence to the middle element of the array
def ham(k, h = h):
# Somehow set the value of k in h
return h
return ham
Which I would then access via
device = Test_device()
device.get_H(k = k_value)
Thanks in advance!
Upvotes: 2
Views: 618
Reputation: 8407
On reflection I do not think np.fromfunction()
is what you want. Rather try:
import numpy as np
class Test_device(object):
def __init__(self, h_shape):
self.h_shape = h_shape
# Create array once
self.h = np.linspace(1, h_shape[0] ** 2, h_shape[1] ** 2).reshape(self.h_shape)
def get_H(self, k, locn=(1, 1)):
self.h[locn] += k # Give some k-dependence to the middle element of the array
# Somehow set the value of k in h
pass
In what follows, initialize device once (given an intended shape for h
). Then choose a k
(and a location locn
, if you want). Then call the get_H
method of device
. k
is never attributed to device
, but could be if you like for reference with self.k=k
(as stated by eatmeinadanish).
Then you can access device.h
whenever you like.
h_shape = (3, 3)
device = Test_device(h_shape)
k = 1.3
locn = (1, 1)
device.get_H(k, locn=locn)
print device.h
I'm not sure this helps you much in the end, whether it's what you actually intended, and note that it doesn't really add much to eatmeinadanish's answer.
Upvotes: 0
Reputation: 3907
This isn't a working example but...
class Test_device():
def __init__(self, h):
self.k = 0
self.h = h
def get_H(self):
self.h = np.linspace(1,9,9).reshape((3,3)) # Test array
# The below clearly will not work because k is not defined, but this is
# where I want to achieve this
self.h[1,1] += self.k # Give some k-dependence to the middle element of the array
def ham(self):
# Somehow set the value of k in h
return self.h
You can do something like this:
device = Test_Device(10)
device.get_H()
device.h = 12
device.get_H()
h = device.ham()
You can change h or k at any time by just changing the value inside the class like device.h = 14
. The same with k.
Upvotes: 0