Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
serial.py
Go to the documentation of this file.
1 # Andrew Gloster
2 # Summer 2016
3 # Python Version of Communication Model Implementation
4 # Functions relating to serial computations and fitting of serial element of the model
5 
6 #------------------------------------
7 # Import relevant modules
8 #------------------------------------
9 
10 from scipy.optimize import fmin
11 import matplotlib.pyplot as plt
12 
13 #------------------------------------
14 # Import relevant functions and classes
15 #------------------------------------
16 
17 import math as m
18 import numpy as np
19 from scipy.optimize import minimize
20 
21 #------------------------------------
22 # New Function
23 #------------------------------------
24 
25 # Compute length of one timestep for given inputs (Model must be fitted prior to this function)
26 def Serial_Computation(P, Num_Elements, Num_Modes, N_P, N_V_1, N_V_2, N_V_3, Num_Constants, constants, Scheme):
27 
28 # Operation Counts as per the thesis
29  O_A_1 = 9 * Num_Elements * (P + 1) ** 2 * Num_Modes * m.log(Num_Modes, 2)
30  O_A_2 = Num_Elements * Num_Modes * (P + 1) ** 2
31  O_A_3 = 6 * Num_Elements * (P + 1) ** 4 * Num_Modes
32  O_A_4 = 15 * Num_Elements * (P + 1) ** 2 * Num_Modes
33 
34  T_A = O_A_1 + O_A_2 + O_A_3 + O_A_4
35 
36  if (Scheme == 'IterativeFull'):
37  O_E_1 = 8 * Num_Elements * (P + 1) ** 2
38  O_E_2 = Num_Elements * (P + 1) ** 2
39  O_E_3 = Num_Elements * ((4 * P ** 3) + (18 * P ** 2) + (26 * P) + 12)
40  O_E_4 = 6 * Num_Elements * (P + 1) ** 2
41 
42  t_e = O_E_1 + O_E_2 + O_E_3 + O_E_4
43 
44  T_E = (N_P + N_V_1 + N_V_2 + N_V_3) * t_e
45 
46  if (Scheme == 'IterativeStaticCond'):
47  O_E_1 = 8 * ((P - 1) ** 2) * 4 * P * Num_Elements * Num_Modes
48  O_E_2 = (N_P + N_V_1 + N_V_2 + N_V_3) * 2 * 16 * (P ** 2) * Num_Elements
49  O_E_3 = (8 * 4 * ((P - 1) ** 2)) + (4 * ((P - 1) ** 2)) * Num_Elements * Num_Modes
50  O_E_4 = 8 * ((((P - 1) ** 2)) ** 2) * Num_Elements * Num_Modes
51 
52  T_E = O_E_1 + O_E_2 + O_E_3 + O_E_4
53 
54 # Divide by operations per second.
55 
56  if (Num_Constants == 1):
57  T_A = T_A / constants
58  T_E = T_E / constants
59 
60  if (Num_Constants == 2):
61  T_A = T_A / constants[0]
62  T_E = T_E / constants[1]
63 
64  Time = T_A + T_E
65 
66  return(Time)
67 
68 #------------------------------------
69 # New Function
70 #------------------------------------
71 
72 def Operation_Count(P, Num_Elements, Num_Modes, N_P, N_V_1, N_V_2, N_V_3, Scheme):
73 
74 # Operation Counts as per the thesis
75  O_A_1 = 9 * Num_Elements * (P + 1) ** 2 * Num_Modes * m.log(Num_Modes, 2)
76  O_A_2 = Num_Elements * Num_Modes * (P + 1) ** 2
77  O_A_3 = 6 * Num_Elements * (P + 1) ** 4 * Num_Modes
78  O_A_4 = 15 * Num_Elements * (P + 1) ** 2 * Num_Modes
79 
80  T_A = O_A_1 + O_A_2 + O_A_3 + O_A_4
81 
82  if (Scheme == 'IterativeFull'):
83  O_E_1 = 8 * Num_Elements * (P + 1) ** 2
84  O_E_2 = Num_Elements * (P + 1) ** 2
85  O_E_3 = Num_Elements * ((4 * P ** 3) + (18 * P ** 2) + (26 * P) + 12)
86  O_E_4 = 6 * Num_Elements * (P + 1) ** 2
87 
88  t_e = O_E_1 + O_E_2 + O_E_3 + O_E_4
89 
90  T_E = (N_P + N_V_1 + N_V_2 + N_V_3) * t_e
91 
92  if (Scheme == 'IterativeStaticCond'):
93  O_E_1 = 8 * ((P - 1) ** 2) * 4 * P * Num_Elements * Num_Modes
94  O_E_2 = (N_P + N_V_1 + N_V_2 + N_V_3) * 2 * 16 * (P ** 2) * Num_Elements
95  O_E_3 = (8 * 4 * ((P - 1) ** 2)) + (4 * ((P - 1) ** 2)) * Num_Elements * Num_Modes
96  O_E_4 = 8 * ((((P - 1) ** 2)) ** 2) * Num_Elements * Num_Modes
97 
98  T_E = O_E_1 + O_E_2 + O_E_3 + O_E_4
99 
100  return(T_A, T_E)
101 
102 #------------------------------------
103 # New Function
104 #------------------------------------
105 
106 # Find the L_2 norm of the difference between the data and model, used for fitting.
107 def compare_data(constants, Num_Constants, Data, T_A, T_E):
108 
109  # Lemons make nice Lemonade (Needed a list to hold results)
110  lemons = []
111 
112  # Loop over data calculating difference between data and model, this will be minimised by the constants.
113  for i in range(0, len(Data)):
114 
115  if (Num_Constants == 1):
116  lemons.append(Data[i] - (T_A[i] + T_E[i])/constants)
117 
118  if (Num_Constants == 2):
119  lemons.append(Data[i] - (T_A[i] / constants[0] + T_E[i] / constants[1]))
120 
121  # Calculate the L_2 norm of the difference, this is the quantity to be minimised by the optimisation step
122  L_2_norm = np.linalg.norm(lemons, 2)
123 
124  return(L_2_norm)
125 
126 #------------------------------------
127 # New Function
128 #------------------------------------
129 
130 # Function to run the fmin optimisation algorithm to fit the model to the data.
131 def Fit_Model(Num_Constants, Data, T_A, T_E):
132 
133  # Numpy arrays to hold the results and data.
134  Data = np.array(Data)
135  T_A = np.array(T_A)
136  T_E = np.array(T_E)
137 
138  # Set the initial values depending on how many constants are required
139  if (Num_Constants == 1):
140  inital = 1e6
141 
142  if (Num_Constants == 2):
143  inital = np.array([1e6, 1e06])
144 
145  # Run the optimisation algorithm
146  Fit = fmin(compare_data, inital, args=(Num_Constants, Data, T_A, T_E), xtol=0.0001, ftol=1, maxiter=1e04, maxfun=1e09)
147 
148  # Return the fitted constants.
149  return(Fit)
150 
151 #------------------------------------
152 # New Function
153 #------------------------------------
154 
155 # Function to run all the steps in order to fit the serial model to serially produced data.
156 def Run_Serial_Fit(Compare_Serial, Consider_Modes, Num_Constants, P, Num_Elements, Nektar_Modes, Timings, Pressure, Velocity_1, Velocity_2, Velocity_3, Scheme):
157 
158  # List to hold data from Nektar simulation
159  Data = []
160 
161  # Loop over modes to be considered in calibrating the model
162  for i in range(0, len(Consider_Modes)):
163  Data.append(np.mean(Timings[str(Consider_Modes[i])])/10)
164 
165  # Lists to hold the operation counts to be fed into the optimisation
166  T_A = []
167  T_E = []
168 
169  # Loop over modes to be used in the model
170  for i in range(0, len(Consider_Modes)):
171 
172  # Initialise CG counters to 0
173  N_P = 0
174  N_V_1 = 0
175  N_V_2 = 0
176  N_V_3 = 0
177 
178  # Loop over all the modes up to the mode being considered adding the CG iterations from each mode to the counter
179  for j in range(1, Consider_Modes[i] + 1):
180 
181  # Skip the 2nd mode as we do not get any data about it from Nektar
182  if (j == 2):
183  continue
184 
185  # We don't necessarily have data for all the CG iterations hence we use try
186  # The except case has to be included to keep python happy hence we pay homage to Alan Turing
187  try:
188  N_P += Pressure[str(j)][0]
189  except:
190  Turing = 'King of Computers'
191 
192  try:
193  N_V_1 += Velocity_1[str(j)][0]
194  except:
195  Turing = 'King of Computers'
196 
197  try:
198  N_V_2 += Velocity_2[str(j)][0]
199  except:
200  Turing = 'King of Computers'
201 
202  try:
203  N_V_3 += Velocity_3[str(j)][0]
204  except:
205  Turing = 'King of Computers'
206 
207  # Perform the operation counts for each mode and store these to be fed into the optimisation step
208  (t_a, t_e) = Operation_Count(P, Num_Elements, Consider_Modes[i], N_P, N_V_1, N_V_2, N_V_3, Scheme)
209  T_A.append(t_a)
210  T_E.append(t_e)
211 
212  # Now fit the model to the data
213  Fit = Fit_Model(Num_Constants, Data, T_A, T_E)
214 
215  # Print the fitted FLOPs
216  print(Fit)
217 
218  # Output the comparison the results if the user desires
219  if Compare_Serial is True:
220 
221  # Pharse the Nektar data as before
222  Data = []
223 
224  for i in range(1, len(Nektar_Modes)):
225  Data.append(np.mean(Timings[str(Nektar_Modes[i])])/10)
226 
227  Time = []
228 
229  for i in range(1, len(Nektar_Modes)):
230  N_P = 0
231  N_V_1 = 0
232  N_V_2 = 0
233  N_V_3 = 0
234 
235  for j in range(1, Nektar_Modes[i] + 1):
236 
237  if (j == 2):
238  continue
239 
240  try:
241  N_P += Pressure[str(j)][0]
242  except:
243  Turing = 'King of Computers'
244 
245  try:
246  N_V_1 += Velocity_1[str(j)][0]
247  except:
248  Turing = 'King of Computers'
249 
250  try:
251  N_V_2 += Velocity_2[str(j)][0]
252  except:
253  Turing = 'King of Computers'
254 
255  try:
256  N_V_3 += Velocity_3[str(j)][0]
257  except:
258  Turing = 'King of Computers'
259 
260  Time.append(Serial_Computation(P, Num_Elements, Nektar_Modes[i], N_P, N_V_1, N_V_2, N_V_3, Num_Constants, Fit, Scheme))
261 
262  Nektar_Modes = list(Nektar_Modes)
263  Nektar_Modes.pop(0)
264 
265  # Calculate the mean, standard deviation and variance of the difference between the data and the fitted model
266  difference = []
267 
268  for i in range(0, len(Nektar_Modes)):
269  difference.append(abs(Data[i] - Time[i]))
270 
271  mean_diff = np.mean(difference)
272  std_dev_diff = np.std(difference)
273  var_diff = np.var(difference)
274 
275  # Print these results for the user to see
276  print('The mean of the differences between the Data and the Model is ' + str(mean_diff))
277  print('The standard deviation of the differences between the Data and the Model is ' + str(std_dev_diff))
278  print('The variance of the differences between the Data and the Model is ' + str(var_diff))
279 
280  # Plot the two data sets together for a visual comparison
281  fig, ax = plt.subplots()
282  ax.plot(Nektar_Modes, Data, label = 'Data')
283  ax.errorbar(Nektar_Modes, Time, label = 'Model')
284  ax.set_xlabel('$ N_Z $')
285  ax.set_ylabel('Timestep (s)')
286  ax.set_title('Length of Single Timestep: Model vs Data')
287  plt.legend(loc=4)
288  fig.savefig("Output/Figures/Model_vs_Data.png")
289 
290  return(Fit)
291 
292 #------------------------------------
293 # End of Functions
294 #------------------------------------
def Fit_Model
Definition: serial.py:131
def Serial_Computation
Definition: serial.py:26
def Run_Serial_Fit
Definition: serial.py:156
def compare_data
Definition: serial.py:107
def Operation_Count
Definition: serial.py:72