Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

import bisect 

import numpy as np 

from m_pool.transform import Transform 

 

class Axis(object): 

'''An Axis object is used to define the axes of Matrix objects 

 

For interpolation, an axis can transform its values to (hopefully) 

make them more linear. (e.g. log10 for an axis spanning orders of magnitude) 

 

*** Structured to easily pickle via a dictionary of named values for properties. *** 

''' 

 

def __init__(self, D={'name':'axisName', 'valueL':None, 'units':'', 

'transform':None, 'roundDigits':4} ): 

'''Initialize with a dictionary so that pickle files can easily save and read objects''' 

 

self.name = D.get('name','Unknown') 

self.valueL = D.get('valueL', [0.0,1.0]) 

self.units = D.get('units','') 

self.transform = D.get('transform','') 

self.transObj = Transform( self.transform ) 

self.roundDigits = D.get('roundDigits', 4) 

 

self.valueL = [float(v) for v in self.valueL] # make sure it's all float 

 

self.matrixConnectionL = [] # holds list of tuple objects (iaxis, matrixObj) 

 

self.make_supt_objects() 

 

def get_pickleable_dict(self): 

return {'name':self.name, 'valueL':self.valueL, 'units':self.units, 

'transform':self.transform, 'roundDigits':self.roundDigits} 

 

def get_valueL(self): 

return self.valueL[:] # return a copy 

 

def __str__(self): 

sL = ['Axis: %s'%self.name + ' ' + str(self.valueL)] 

return '\n'.join(sL) 

 

def __len__(self): 

return len( self.valueL ) 

 

def __iter__(self): 

for value in self.valueL: 

yield value 

 

def __getitem__(self, i): # retrieve as: A[i] 

return self.valueL[i] 

 

def connectMatrix(self, iaxis, matrixObj): 

'''Save all connections to Matrix objects''' 

# Save a tuple of index position in Matrix and Matrix itself 

self.matrixConnectionL.append( (iaxis,matrixObj) ) 

 

 

def make_supt_objects(self): 

self.valueArr = np.array( self.valueL ) 

# Keep a transformed array for later linear interpolation  

self.transArr = self.transObj( self.valueArr ) 

 

self.indexD = {} # quickly look up index from value 

for i,val in enumerate(self.valueL): 

self.indexD[val] = i 

self.indexD[ self.valueArr[i] ] = i # works for both float and np.float 

 

def getQuadterpIndex(self, val): 

'''Index used for quad_terp interpolation''' 

val = float(val) 

i = bisect.bisect_left(self.valueArr, val) - 1 

 

if i<0: 

return 0 

elif i>self.valueArr.size-3: 

return self.valueArr.size-3 

return i 

 

def getExactIndex(self, val): 

'''Get Index into self.valueL from the val input''' 

val = float(val) # make sure it's a float 

try: 

i = self.indexD[val] # if it's in the cross-index, use it 

return i 

except: 

pass 

 

# Otherwise, see if val is within roundoff error of an included value 

i = bisect.bisect_left( self.valueL, val ) 

try: 

#print ' Round A i=%i'%i,round(val, self.roundDigits),round(self.valueL[i], self.roundDigits) 

if round(val, self.roundDigits)==round(self.valueL[i], self.roundDigits): 

return i 

except: 

pass 

 

try: 

#print ' Round B i=%i'%i,round(val, self.roundDigits),round(self.valueL[i-1], self.roundDigits) 

if round(val, self.roundDigits)==round(self.valueL[i-1], self.roundDigits): 

return i-1 

except: 

pass 

 

return None # Can't find the index... return None 

 

 

def add_value(self, val): 

val = float(val) 

i = bisect.bisect_left( self.valueL, val ) 

if i>= len(self.valueL): 

self.valueL.append( val ) 

 

else: 

if self.valueL[i]==val: 

print(val,'is already in Axis... skipping insert') 

return None 

 

#print 'i=',i,'for',val,'inserted into',self.valueL,'v[i]=',self.valueL[i] 

self.valueL.insert(i,val) 

#print 'new vL=',self.valueL 

self.make_supt_objects() 

 

for iaxis,M in self.matrixConnectionL: 

M.insert_dimension( iaxis,i ) 

 

return i # calling routine might need insertion point 

 

 

if __name__=="__main__": 

 

epsAxis = Axis({'name':'eps', 'valueL':[1.,2.,3.,5.,10.,20.,40.], 'units':'', 'transform':'log10'}) 

print(epsAxis.get_pickleable_dict()) 

print() 

print('epsAxis.transArr =',epsAxis.transArr) 

print() 

epsAxis.add_value( 1.6 ) 

epsAxis.add_value( 1.5 ) 

epsAxis.add_value( 7 ) 

epsAxis.add_value( 40.0001 ) 

epsAxis.add_value( 0.0 ) 

print(epsAxis.valueArr) 

print('len(epsAxis) =',len(epsAxis)) 

print() 

for val in [0, -1.1, 0.5, 1, 1.25, 4,40, 40.0001, 40.00001, 40.000001]: 

 

i = epsAxis.getExactIndex(val) 

if i==None: 

print('for val=',val,' i=',i) 

else: 

print('for val=',val,' i=%i'%i, ' valueL[i]=',epsAxis.valueL[i])