fpex0.setup
1from copy import copy 2 3import numpy as np 4from scipy.integrate import solve_ivp 5from scipy import interpolate 6 7from .fokker_planck import FokkerPlanck 8 9 10class DSC_Data: 11 """ 12 Class for dsc data. Stores unprocessed and processed data. 13 14 ## Parameters 15 **mass** 16 <br> Sample mass. 17 18 **rate** 19 <br> Heating rate. 20 21 **T** 22 <br> Temperatures. 23 24 **dsc** 25 <br> Corresponding raw DSC measurements. 26 27 **bldata** 28 <br> Information about the baselevel. 29 30 **blfun** 31 <br> Baselevel function as retrieved by `fpex0.baseline.getBaseline`. 32 33 **cp** 34 <br> Calculated heat capacities as HeatCapacitiy member. 35 36 **ID** 37 <br> Name/identifier of experiment. 38 """ 39 def __init__(self, T=None, dsc=None, mass=None, rate=None, bldata=None, blfun=None, cp=None, ID=None): 40 self.mass = mass 41 self.rate = rate 42 self.T = T 43 self.dsc = dsc 44 self.bldata = bldata 45 self.blfun = blfun 46 self.cp = cp 47 self.ID = ID 48 49 50 51class Setup: 52 """ 53 FPEX0 configuration. 54 55 ## Parameters : `fpex0.setup.Grid` 56 **Grid** 57 <br> A discretization grid for Fokker-Planck. 58 59 **Parameters** 60 <br> A collection of parameters and boudns, 61 instance of `fpex0.setup.Parameters`. 62 63 **Integration** : `fpex0.setup.Integration` 64 <br> Represents an integrator to solve our discretization of Fokker-Planck. 65 66 **FPdriftFcn** 67 <br> Function object of Fokker-Planck drift. 68 69 **FPdiffusionFcn** 70 <br> Function object of Fokker-Planck diffusion. 71 72 **IniDistFcn** 73 <br> Function object of inital distribution. 74 """ 75 def __init__(self, Grid, Parameters : dict, Integration, FPdriftFcn, FPdiffusionFcn, IniDistFcn): 76 self.Grid = Grid 77 self.Parameters = Parameters 78 self.Integration = Integration 79 self.FPdriftFcn = FPdriftFcn 80 self.FPdiffusionFcn = FPdiffusionFcn 81 self.IniDistFcn = IniDistFcn 82 83 self.Measurements = Measurements() 84 85 86 def make_rhsFcn(self, p_FPdrift, p_FPdiffusion): 87 """ 88 Generator for the ODEs right-hand-side. 89 """ 90 h = self.Grid.h 91 FPdriftFcn = self.FPdriftFcn 92 FPdiffusionFcn = self.FPdiffusionFcn 93 94 rhsFcn = lambda t,u: FokkerPlanck.FokkerPlanckODE(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 95 return rhsFcn 96 97 98 def make_jacFcn(self, p_FPdrift, p_FPdiffusion): 99 """ 100 Generator for the ODEs jacobian. 101 """ 102 fokker_planck = FokkerPlanck() 103 jacFcn = lambda t,u: fokker_planck.FokkerPlanckODE_dfdu(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 104 return jacFcn 105 106 107 def importMeasurements(self, T, values, heatrate, ID=None, gridskip=1): 108 """ 109 Imports measurements into FPEX0setup (`fpex0.setup.Measurements`). 110 An interpolation to the integration grid is performed and the interpolated values are stored. 111 112 ## Takes 113 **FPEX0setup** 114 <br> FPEX0_class_setup object. 115 116 **ID** 117 <br> Name/identifier of experiment. 118 119 **heatrate** 120 <br> Heating rate. 121 122 **T** 123 <br> Temperature grid / measurement positions. 124 125 **values** 126 <br> Measurement values (e.g. cp-values); 127 where values[k] denotes the measurement value at T[k]. 128 129 **gridskip** 130 <br> Use grid with given stepsize (gridskip). 131 <br> For gridskip=2 for example, only every second grid point is used, 132 whereas gridskip=1 uses the whole grid. 133 134 135 ## Returns 136 No return value. 137 """ 138 139 # ensure that the rate (=time) lies inside the gridTdot 140 if heatrate < self.Grid.gridTdot[0] or heatrate > self.Grid.gridTdot[-1]: 141 print(f'importMeasurements: Specified rate {heatrate} outside grid bounds [{self.Grid.gridTdot[0]}, {self.Grid.gridTdot[-1]}] !') 142 143 # ensure we have a single column 144 rawT = np.reshape(T , -1) # passing -1 creates a 1d array 145 values = np.reshape(values, -1) 146 147 # interpolate values to gridT respecting gridskip 148 rawValues = values 149 temperatures = self.Grid.gridT[::gridskip] 150 interp = interpolate.PchipInterpolator(rawT, rawValues, extrapolate=False) 151 values = interp(temperatures) 152 values = np.where(np.isnan(values), 0, values) # replace NaN by 0 153 154 # add measurements 155 self.Measurements.appendMeasurement(rawT, temperatures, rawValues, values, heatrate, ID) 156 157 158 def importDSCobject(self, DSC_Data, gridskip=1): 159 # T, values, heatrate, ID=None, gridskip=1 160 161 if type(DSC_Data) is list: 162 for i in range(len(DSC_Data)): 163 self.importDSCobject(DSC_Data[i], gridskip) 164 return 165 166 T = DSC_Data.T 167 # use cp data if available, raw dsc otherwise 168 if DSC_Data.cp is not None: 169 values = DSC_Data.cp 170 else: 171 values = DSC_Data.dsc 172 print("WARNING: Using unprocessed dsc data. Make sure it is baseline-corrected!") 173 heatrate = DSC_Data.rate 174 ID = DSC_Data.ID 175 176 self.importMeasurements(T, values, heatrate, ID, gridskip) 177 178 179class Parameters: 180 """ 181 ## Parameters 182 183 **p0** 184 <br> Full initial parameter vector. 185 186 **p_lb** 187 <br> Full parameter lower bound vector. 188 189 **p_ub** 190 <br> Full parameter upper bound vector. 191 192 **p0_FPdrift** 193 <br> Initial drift parameter vector. 194 195 **p0_FPdiffusion** 196 <br> Initial diffusion parameter vector. 197 198 **p0_iniDist** 199 <br> Initial paramater vector for initial distribution. 200 201 **p_lb_FPdrift** 202 <br> Lower bound vector for drift parameters. 203 204 **p_lb_FPdiffusion** 205 <br> ... 206 207 **p_lb_iniDist** 208 <br> ... 209 210 **p_ub_FPdrift** 211 <br> Upper bound vector for drift parameters. 212 213 **p_ub_FPdiffusion** 214 <br> ... 215 216 **p_ub_iniDist** 217 <br> ... 218 219 **idxFPdrift** 220 <br> Indices of drift parameters in p0 (resp. p_lb, p_ub). 221 222 **idxFPdiffusion** 223 <br> Same thing, diffusion parameters. 224 225 **idxFPall** 226 <br> Same thing, all Fokker-Planck parameters. 227 228 **idxIniDist** 229 <br> Same thing, initial distribution parameters. 230 """ 231 def __init__(self, p0_FPdrift, p0_FPdiffusion, p0_iniDist, 232 p_lb_FPdrift=None, p_lb_FPdiffusion=None, p_lb_iniDist=None, 233 p_ub_FPdrift=None, p_ub_FPdiffusion=None, p_ub_iniDist=None ): 234 235 # ensure matching lengths 236 assert(p_lb_FPdrift is None or len(p0_FPdrift) == len(p_lb_FPdrift) 237 and p_ub_FPdrift is None or len(p0_FPdrift) == len(p_ub_FPdrift)) 238 239 assert(p_lb_FPdiffusion is None or len(p0_FPdiffusion) == len(p_lb_FPdiffusion) 240 and p_ub_FPdiffusion is None or len(p0_FPdiffusion) == len(p_ub_FPdiffusion)) 241 242 assert(p_lb_iniDist is None or len(p0_iniDist) == len(p_lb_iniDist) 243 and p_ub_iniDist is None or len(p0_iniDist) == len(p_ub_iniDist)) 244 245 # initial parameters 246 self.p0_FPdrift = p0_FPdrift 247 self.p0_FPdiffusion = p0_FPdiffusion 248 self.p0_iniDist = p0_iniDist 249 250 # lower parameter bounds 251 # set to vectors of -np.inf if not given 252 if p_lb_FPdrift is None: 253 self.p_lb_FPdrift = np.full(len(p0_FPdrift), -np.inf) 254 else: 255 self.p_lb_FPdrift = p_lb_FPdrift 256 257 if p_lb_FPdiffusion is None: 258 self.p_lb_FPdiffusion = np.full(len(p0_FPdiffusion), -np.inf) 259 else: 260 self.p_lb_FPdiffusion = p_lb_FPdiffusion 261 262 if p_lb_iniDist is None: 263 self.p_lb_iniDist = np.full(len(p0_iniDist), -np.inf) 264 else: 265 self.p_lb_iniDist = p_lb_iniDist 266 267 # upper parameter bounds 268 # set to vectors of np.inf if not given 269 if p_ub_FPdrift is None: 270 self.p_ub_FPdrift = np.full(len(p0_FPdrift), np.inf) 271 else: 272 self.p_ub_FPdrift = p_ub_FPdrift 273 274 if p_ub_FPdiffusion is None: 275 self.p_ub_FPdiffusion = np.full(len(p0_FPdiffusion), np.inf) 276 else: 277 self.p_ub_FPdiffusion = p_ub_FPdiffusion 278 279 if p_ub_iniDist is None: 280 self.p_ub_iniDist = np.full(len(p0_iniDist), np.inf) 281 else: 282 self.p_ub_iniDist = p_ub_iniDist 283 284 # put initials, lower and upper bounds in one vector each 285 self.p0 = np.concatenate((p0_FPdrift, p0_FPdiffusion, p0_iniDist)) 286 self.p_lb = np.concatenate((p_lb_FPdrift, p_lb_FPdiffusion, p_lb_iniDist)) 287 self.p_ub = np.concatenate((p_ub_FPdrift, p_ub_FPdiffusion, p_ub_iniDist)) 288 289 # indices 290 self.idxFPdrift = np.arange(0, len(p0_FPdrift) ) 291 self.idxFPdiffusion = np.arange(0, len(p0_FPdiffusion) ) + len(p0_FPdrift) 292 self.idxFPall = np.arange(0, len(p0_FPdrift)+len(p0_FPdiffusion) ) 293 self.idxIniDist = np.arange(0, len(p0_iniDist) ) + ( len(p0_FPdrift) + len(p0_FPdiffusion) ) 294 295 296 # extractor functions for external parameter vector (alike self.p0) 297 def extract_p_all(self, pvec): 298 return pvec 299 300 def extract_p_FPdrift(self, pvec): 301 return pvec[self.idxFPdrift] 302 303 def extract_p_FPdiffusion(self, pvec): 304 return pvec[self.idxFPdiffusion] 305 306 def extract_p_FPall(self, pvec): 307 return pvec[self.idxFPall] 308 309 def extract_p_iniDist(self, pvec): 310 return pvec[self.idxIniDist] 311 312 313 # setter functions (TODO: Set parameters in the vectors.) 314 def set_p0(self, p0): 315 self.p0 = p0 316 317 def set_p_lb(self, p_lb): 318 assert(len(p_lb) == len(self.p0)) 319 self.p_lb = p_lb 320 321 def set_p_ub(self, p_ub): 322 assert(len(p_ub) == len(self.p0)) 323 self.p_ub = p_ub 324 325 326 327class Grid: 328 """ 329 FPEX0 discretization(?) grid. 330 331 ## Parameters 332 **gridT** 333 <br> x-grid = temperatures 334 <br> This is our method of lines discretization grid. 335 336 **gridTdot** 337 <br> t-grid = heating rates 338 339 **N** 340 <br> Number of grid points. 341 342 **h** 343 <br> Grid size. 344 """ 345 def __init__(self, gridT, gridTdot): 346 self.gridT = gridT 347 self.gridTdot = gridTdot 348 self.N = len(gridT) 349 self.h = ( gridT[-1] - gridT[0] ) / self.N 350 351 352 353class Measurements: 354 """ 355 Stores measurement data in list containers. 356 357 ## Parameters 358 **rawT** 359 <br> Measurement temperatures. 360 361 **temperatures** 362 <br> Selected temperatures from temperature grid. 363 364 **rawValues** 365 <br> Raw masurement values. 366 367 **values** 368 <br> rawValues interpolated to grid. 369 370 **rates** 371 <br> Heat rates. 372 373 **ID** 374 <br> Experiment name/identifier. 375 """ 376 def __init__(self, rawT=[], temperatures=[], rawValues=[], values=[], rates=[], ID=[]): 377 self.rawT = rawT 378 self.temperatures = temperatures 379 self.rawValues = rawValues 380 self.rates = rates 381 self.ID = ID 382 self.values = values 383 384 def appendMeasurement(self, new_T, new_temperatures, new_rawValues, new_values, new_rate, new_ID=None): 385 """ 386 Appends given measurements to the measurement parameters. 387 """ 388 self.rawT.append(new_T) 389 self.temperatures.append(new_temperatures) 390 self.rawValues.append(new_rawValues) 391 self.values.append(new_values) 392 self.rates.append(new_rate) 393 self.ID.append(new_ID) 394 395 396 397class Integration: 398 """ 399 Represents FPEX0 integrator. 400 401 ## Parameters 402 **method** 403 <br> Method to use by scipy solve_ivp. Default is BDF. 404 405 **options** 406 <br> Integration options. Currently not used. 407 408 **integrator** 409 <br> Integrator for ODEs. Should have the signature integrator(FPrhs, t0tf, u0, method). 410 411 **NN, A, B**: Internal variables used by FokkerPlanckODE_dfdu. 412 """ 413 # (TODO) Set default tolerances in Integration class (?) 414 def __init__(self, integrator=solve_ivp, method="BDF", options={}): 415 self.method = method 416 self.options = options 417 self.integrator = integrator 418 self.NN = None # variables for FokkerPlanckODE_dfdu() 419 self.A = None 420 self.B = None 421 422 def updateOptions(self, newOptions): 423 """ Returns the integrators options. """ 424 options = copy(self.options) 425 for key in newOptions: 426 options[key] = newOptions[key] 427 self.options = options 428 return options 429 430 431 def updateJacobian(self, jacobianFcn): 432 """ Returns an option dictionary with updated jacobian. """ 433 options = copy(self.options) 434 options["jac"] = jacobianFcn 435 self.options = options 436 return options 437
11class DSC_Data: 12 """ 13 Class for dsc data. Stores unprocessed and processed data. 14 15 ## Parameters 16 **mass** 17 <br> Sample mass. 18 19 **rate** 20 <br> Heating rate. 21 22 **T** 23 <br> Temperatures. 24 25 **dsc** 26 <br> Corresponding raw DSC measurements. 27 28 **bldata** 29 <br> Information about the baselevel. 30 31 **blfun** 32 <br> Baselevel function as retrieved by `fpex0.baseline.getBaseline`. 33 34 **cp** 35 <br> Calculated heat capacities as HeatCapacitiy member. 36 37 **ID** 38 <br> Name/identifier of experiment. 39 """ 40 def __init__(self, T=None, dsc=None, mass=None, rate=None, bldata=None, blfun=None, cp=None, ID=None): 41 self.mass = mass 42 self.rate = rate 43 self.T = T 44 self.dsc = dsc 45 self.bldata = bldata 46 self.blfun = blfun 47 self.cp = cp 48 self.ID = ID
Class for dsc data. Stores unprocessed and processed data.
Parameters
mass
Sample mass.
rate
Heating rate.
T
Temperatures.
dsc
Corresponding raw DSC measurements.
bldata
Information about the baselevel.
blfun
Baselevel function as retrieved by fpex0.baseline.getBaseline
.
cp
Calculated heat capacities as HeatCapacitiy member.
ID
Name/identifier of experiment.
52class Setup: 53 """ 54 FPEX0 configuration. 55 56 ## Parameters : `fpex0.setup.Grid` 57 **Grid** 58 <br> A discretization grid for Fokker-Planck. 59 60 **Parameters** 61 <br> A collection of parameters and boudns, 62 instance of `fpex0.setup.Parameters`. 63 64 **Integration** : `fpex0.setup.Integration` 65 <br> Represents an integrator to solve our discretization of Fokker-Planck. 66 67 **FPdriftFcn** 68 <br> Function object of Fokker-Planck drift. 69 70 **FPdiffusionFcn** 71 <br> Function object of Fokker-Planck diffusion. 72 73 **IniDistFcn** 74 <br> Function object of inital distribution. 75 """ 76 def __init__(self, Grid, Parameters : dict, Integration, FPdriftFcn, FPdiffusionFcn, IniDistFcn): 77 self.Grid = Grid 78 self.Parameters = Parameters 79 self.Integration = Integration 80 self.FPdriftFcn = FPdriftFcn 81 self.FPdiffusionFcn = FPdiffusionFcn 82 self.IniDistFcn = IniDistFcn 83 84 self.Measurements = Measurements() 85 86 87 def make_rhsFcn(self, p_FPdrift, p_FPdiffusion): 88 """ 89 Generator for the ODEs right-hand-side. 90 """ 91 h = self.Grid.h 92 FPdriftFcn = self.FPdriftFcn 93 FPdiffusionFcn = self.FPdiffusionFcn 94 95 rhsFcn = lambda t,u: FokkerPlanck.FokkerPlanckODE(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 96 return rhsFcn 97 98 99 def make_jacFcn(self, p_FPdrift, p_FPdiffusion): 100 """ 101 Generator for the ODEs jacobian. 102 """ 103 fokker_planck = FokkerPlanck() 104 jacFcn = lambda t,u: fokker_planck.FokkerPlanckODE_dfdu(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 105 return jacFcn 106 107 108 def importMeasurements(self, T, values, heatrate, ID=None, gridskip=1): 109 """ 110 Imports measurements into FPEX0setup (`fpex0.setup.Measurements`). 111 An interpolation to the integration grid is performed and the interpolated values are stored. 112 113 ## Takes 114 **FPEX0setup** 115 <br> FPEX0_class_setup object. 116 117 **ID** 118 <br> Name/identifier of experiment. 119 120 **heatrate** 121 <br> Heating rate. 122 123 **T** 124 <br> Temperature grid / measurement positions. 125 126 **values** 127 <br> Measurement values (e.g. cp-values); 128 where values[k] denotes the measurement value at T[k]. 129 130 **gridskip** 131 <br> Use grid with given stepsize (gridskip). 132 <br> For gridskip=2 for example, only every second grid point is used, 133 whereas gridskip=1 uses the whole grid. 134 135 136 ## Returns 137 No return value. 138 """ 139 140 # ensure that the rate (=time) lies inside the gridTdot 141 if heatrate < self.Grid.gridTdot[0] or heatrate > self.Grid.gridTdot[-1]: 142 print(f'importMeasurements: Specified rate {heatrate} outside grid bounds [{self.Grid.gridTdot[0]}, {self.Grid.gridTdot[-1]}] !') 143 144 # ensure we have a single column 145 rawT = np.reshape(T , -1) # passing -1 creates a 1d array 146 values = np.reshape(values, -1) 147 148 # interpolate values to gridT respecting gridskip 149 rawValues = values 150 temperatures = self.Grid.gridT[::gridskip] 151 interp = interpolate.PchipInterpolator(rawT, rawValues, extrapolate=False) 152 values = interp(temperatures) 153 values = np.where(np.isnan(values), 0, values) # replace NaN by 0 154 155 # add measurements 156 self.Measurements.appendMeasurement(rawT, temperatures, rawValues, values, heatrate, ID) 157 158 159 def importDSCobject(self, DSC_Data, gridskip=1): 160 # T, values, heatrate, ID=None, gridskip=1 161 162 if type(DSC_Data) is list: 163 for i in range(len(DSC_Data)): 164 self.importDSCobject(DSC_Data[i], gridskip) 165 return 166 167 T = DSC_Data.T 168 # use cp data if available, raw dsc otherwise 169 if DSC_Data.cp is not None: 170 values = DSC_Data.cp 171 else: 172 values = DSC_Data.dsc 173 print("WARNING: Using unprocessed dsc data. Make sure it is baseline-corrected!") 174 heatrate = DSC_Data.rate 175 ID = DSC_Data.ID 176 177 self.importMeasurements(T, values, heatrate, ID, gridskip)
FPEX0 configuration.
Parameters : fpex0.setup.Grid
Grid
A discretization grid for Fokker-Planck.
Parameters
A collection of parameters and boudns,
instance of fpex0.setup.Parameters
.
Integration : fpex0.setup.Integration
Represents an integrator to solve our discretization of Fokker-Planck.
FPdriftFcn
Function object of Fokker-Planck drift.
FPdiffusionFcn
Function object of Fokker-Planck diffusion.
IniDistFcn
Function object of inital distribution.
76 def __init__(self, Grid, Parameters : dict, Integration, FPdriftFcn, FPdiffusionFcn, IniDistFcn): 77 self.Grid = Grid 78 self.Parameters = Parameters 79 self.Integration = Integration 80 self.FPdriftFcn = FPdriftFcn 81 self.FPdiffusionFcn = FPdiffusionFcn 82 self.IniDistFcn = IniDistFcn 83 84 self.Measurements = Measurements()
87 def make_rhsFcn(self, p_FPdrift, p_FPdiffusion): 88 """ 89 Generator for the ODEs right-hand-side. 90 """ 91 h = self.Grid.h 92 FPdriftFcn = self.FPdriftFcn 93 FPdiffusionFcn = self.FPdiffusionFcn 94 95 rhsFcn = lambda t,u: FokkerPlanck.FokkerPlanckODE(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 96 return rhsFcn
Generator for the ODEs right-hand-side.
99 def make_jacFcn(self, p_FPdrift, p_FPdiffusion): 100 """ 101 Generator for the ODEs jacobian. 102 """ 103 fokker_planck = FokkerPlanck() 104 jacFcn = lambda t,u: fokker_planck.FokkerPlanckODE_dfdu(t, u, self.Grid.h, self.FPdriftFcn, p_FPdrift, self.FPdiffusionFcn, p_FPdiffusion) 105 return jacFcn
Generator for the ODEs jacobian.
108 def importMeasurements(self, T, values, heatrate, ID=None, gridskip=1): 109 """ 110 Imports measurements into FPEX0setup (`fpex0.setup.Measurements`). 111 An interpolation to the integration grid is performed and the interpolated values are stored. 112 113 ## Takes 114 **FPEX0setup** 115 <br> FPEX0_class_setup object. 116 117 **ID** 118 <br> Name/identifier of experiment. 119 120 **heatrate** 121 <br> Heating rate. 122 123 **T** 124 <br> Temperature grid / measurement positions. 125 126 **values** 127 <br> Measurement values (e.g. cp-values); 128 where values[k] denotes the measurement value at T[k]. 129 130 **gridskip** 131 <br> Use grid with given stepsize (gridskip). 132 <br> For gridskip=2 for example, only every second grid point is used, 133 whereas gridskip=1 uses the whole grid. 134 135 136 ## Returns 137 No return value. 138 """ 139 140 # ensure that the rate (=time) lies inside the gridTdot 141 if heatrate < self.Grid.gridTdot[0] or heatrate > self.Grid.gridTdot[-1]: 142 print(f'importMeasurements: Specified rate {heatrate} outside grid bounds [{self.Grid.gridTdot[0]}, {self.Grid.gridTdot[-1]}] !') 143 144 # ensure we have a single column 145 rawT = np.reshape(T , -1) # passing -1 creates a 1d array 146 values = np.reshape(values, -1) 147 148 # interpolate values to gridT respecting gridskip 149 rawValues = values 150 temperatures = self.Grid.gridT[::gridskip] 151 interp = interpolate.PchipInterpolator(rawT, rawValues, extrapolate=False) 152 values = interp(temperatures) 153 values = np.where(np.isnan(values), 0, values) # replace NaN by 0 154 155 # add measurements 156 self.Measurements.appendMeasurement(rawT, temperatures, rawValues, values, heatrate, ID)
Imports measurements into FPEX0setup (fpex0.setup.Measurements
).
An interpolation to the integration grid is performed and the interpolated values are stored.
Takes
FPEX0setup
FPEX0_class_setup object.
ID
Name/identifier of experiment.
heatrate
Heating rate.
T
Temperature grid / measurement positions.
values
Measurement values (e.g. cp-values);
where values[k] denotes the measurement value at T[k].
gridskip
Use grid with given stepsize (gridskip).
For gridskip=2 for example, only every second grid point is used,
whereas gridskip=1 uses the whole grid.
Returns
No return value.
159 def importDSCobject(self, DSC_Data, gridskip=1): 160 # T, values, heatrate, ID=None, gridskip=1 161 162 if type(DSC_Data) is list: 163 for i in range(len(DSC_Data)): 164 self.importDSCobject(DSC_Data[i], gridskip) 165 return 166 167 T = DSC_Data.T 168 # use cp data if available, raw dsc otherwise 169 if DSC_Data.cp is not None: 170 values = DSC_Data.cp 171 else: 172 values = DSC_Data.dsc 173 print("WARNING: Using unprocessed dsc data. Make sure it is baseline-corrected!") 174 heatrate = DSC_Data.rate 175 ID = DSC_Data.ID 176 177 self.importMeasurements(T, values, heatrate, ID, gridskip)
180class Parameters: 181 """ 182 ## Parameters 183 184 **p0** 185 <br> Full initial parameter vector. 186 187 **p_lb** 188 <br> Full parameter lower bound vector. 189 190 **p_ub** 191 <br> Full parameter upper bound vector. 192 193 **p0_FPdrift** 194 <br> Initial drift parameter vector. 195 196 **p0_FPdiffusion** 197 <br> Initial diffusion parameter vector. 198 199 **p0_iniDist** 200 <br> Initial paramater vector for initial distribution. 201 202 **p_lb_FPdrift** 203 <br> Lower bound vector for drift parameters. 204 205 **p_lb_FPdiffusion** 206 <br> ... 207 208 **p_lb_iniDist** 209 <br> ... 210 211 **p_ub_FPdrift** 212 <br> Upper bound vector for drift parameters. 213 214 **p_ub_FPdiffusion** 215 <br> ... 216 217 **p_ub_iniDist** 218 <br> ... 219 220 **idxFPdrift** 221 <br> Indices of drift parameters in p0 (resp. p_lb, p_ub). 222 223 **idxFPdiffusion** 224 <br> Same thing, diffusion parameters. 225 226 **idxFPall** 227 <br> Same thing, all Fokker-Planck parameters. 228 229 **idxIniDist** 230 <br> Same thing, initial distribution parameters. 231 """ 232 def __init__(self, p0_FPdrift, p0_FPdiffusion, p0_iniDist, 233 p_lb_FPdrift=None, p_lb_FPdiffusion=None, p_lb_iniDist=None, 234 p_ub_FPdrift=None, p_ub_FPdiffusion=None, p_ub_iniDist=None ): 235 236 # ensure matching lengths 237 assert(p_lb_FPdrift is None or len(p0_FPdrift) == len(p_lb_FPdrift) 238 and p_ub_FPdrift is None or len(p0_FPdrift) == len(p_ub_FPdrift)) 239 240 assert(p_lb_FPdiffusion is None or len(p0_FPdiffusion) == len(p_lb_FPdiffusion) 241 and p_ub_FPdiffusion is None or len(p0_FPdiffusion) == len(p_ub_FPdiffusion)) 242 243 assert(p_lb_iniDist is None or len(p0_iniDist) == len(p_lb_iniDist) 244 and p_ub_iniDist is None or len(p0_iniDist) == len(p_ub_iniDist)) 245 246 # initial parameters 247 self.p0_FPdrift = p0_FPdrift 248 self.p0_FPdiffusion = p0_FPdiffusion 249 self.p0_iniDist = p0_iniDist 250 251 # lower parameter bounds 252 # set to vectors of -np.inf if not given 253 if p_lb_FPdrift is None: 254 self.p_lb_FPdrift = np.full(len(p0_FPdrift), -np.inf) 255 else: 256 self.p_lb_FPdrift = p_lb_FPdrift 257 258 if p_lb_FPdiffusion is None: 259 self.p_lb_FPdiffusion = np.full(len(p0_FPdiffusion), -np.inf) 260 else: 261 self.p_lb_FPdiffusion = p_lb_FPdiffusion 262 263 if p_lb_iniDist is None: 264 self.p_lb_iniDist = np.full(len(p0_iniDist), -np.inf) 265 else: 266 self.p_lb_iniDist = p_lb_iniDist 267 268 # upper parameter bounds 269 # set to vectors of np.inf if not given 270 if p_ub_FPdrift is None: 271 self.p_ub_FPdrift = np.full(len(p0_FPdrift), np.inf) 272 else: 273 self.p_ub_FPdrift = p_ub_FPdrift 274 275 if p_ub_FPdiffusion is None: 276 self.p_ub_FPdiffusion = np.full(len(p0_FPdiffusion), np.inf) 277 else: 278 self.p_ub_FPdiffusion = p_ub_FPdiffusion 279 280 if p_ub_iniDist is None: 281 self.p_ub_iniDist = np.full(len(p0_iniDist), np.inf) 282 else: 283 self.p_ub_iniDist = p_ub_iniDist 284 285 # put initials, lower and upper bounds in one vector each 286 self.p0 = np.concatenate((p0_FPdrift, p0_FPdiffusion, p0_iniDist)) 287 self.p_lb = np.concatenate((p_lb_FPdrift, p_lb_FPdiffusion, p_lb_iniDist)) 288 self.p_ub = np.concatenate((p_ub_FPdrift, p_ub_FPdiffusion, p_ub_iniDist)) 289 290 # indices 291 self.idxFPdrift = np.arange(0, len(p0_FPdrift) ) 292 self.idxFPdiffusion = np.arange(0, len(p0_FPdiffusion) ) + len(p0_FPdrift) 293 self.idxFPall = np.arange(0, len(p0_FPdrift)+len(p0_FPdiffusion) ) 294 self.idxIniDist = np.arange(0, len(p0_iniDist) ) + ( len(p0_FPdrift) + len(p0_FPdiffusion) ) 295 296 297 # extractor functions for external parameter vector (alike self.p0) 298 def extract_p_all(self, pvec): 299 return pvec 300 301 def extract_p_FPdrift(self, pvec): 302 return pvec[self.idxFPdrift] 303 304 def extract_p_FPdiffusion(self, pvec): 305 return pvec[self.idxFPdiffusion] 306 307 def extract_p_FPall(self, pvec): 308 return pvec[self.idxFPall] 309 310 def extract_p_iniDist(self, pvec): 311 return pvec[self.idxIniDist] 312 313 314 # setter functions (TODO: Set parameters in the vectors.) 315 def set_p0(self, p0): 316 self.p0 = p0 317 318 def set_p_lb(self, p_lb): 319 assert(len(p_lb) == len(self.p0)) 320 self.p_lb = p_lb 321 322 def set_p_ub(self, p_ub): 323 assert(len(p_ub) == len(self.p0)) 324 self.p_ub = p_ub
Parameters
p0
Full initial parameter vector.
p_lb
Full parameter lower bound vector.
p_ub
Full parameter upper bound vector.
p0_FPdrift
Initial drift parameter vector.
p0_FPdiffusion
Initial diffusion parameter vector.
p0_iniDist
Initial paramater vector for initial distribution.
p_lb_FPdrift
Lower bound vector for drift parameters.
p_lb_FPdiffusion
...
p_lb_iniDist
...
p_ub_FPdrift
Upper bound vector for drift parameters.
p_ub_FPdiffusion
...
p_ub_iniDist
...
idxFPdrift
Indices of drift parameters in p0 (resp. p_lb, p_ub).
idxFPdiffusion
Same thing, diffusion parameters.
idxFPall
Same thing, all Fokker-Planck parameters.
idxIniDist
Same thing, initial distribution parameters.
232 def __init__(self, p0_FPdrift, p0_FPdiffusion, p0_iniDist, 233 p_lb_FPdrift=None, p_lb_FPdiffusion=None, p_lb_iniDist=None, 234 p_ub_FPdrift=None, p_ub_FPdiffusion=None, p_ub_iniDist=None ): 235 236 # ensure matching lengths 237 assert(p_lb_FPdrift is None or len(p0_FPdrift) == len(p_lb_FPdrift) 238 and p_ub_FPdrift is None or len(p0_FPdrift) == len(p_ub_FPdrift)) 239 240 assert(p_lb_FPdiffusion is None or len(p0_FPdiffusion) == len(p_lb_FPdiffusion) 241 and p_ub_FPdiffusion is None or len(p0_FPdiffusion) == len(p_ub_FPdiffusion)) 242 243 assert(p_lb_iniDist is None or len(p0_iniDist) == len(p_lb_iniDist) 244 and p_ub_iniDist is None or len(p0_iniDist) == len(p_ub_iniDist)) 245 246 # initial parameters 247 self.p0_FPdrift = p0_FPdrift 248 self.p0_FPdiffusion = p0_FPdiffusion 249 self.p0_iniDist = p0_iniDist 250 251 # lower parameter bounds 252 # set to vectors of -np.inf if not given 253 if p_lb_FPdrift is None: 254 self.p_lb_FPdrift = np.full(len(p0_FPdrift), -np.inf) 255 else: 256 self.p_lb_FPdrift = p_lb_FPdrift 257 258 if p_lb_FPdiffusion is None: 259 self.p_lb_FPdiffusion = np.full(len(p0_FPdiffusion), -np.inf) 260 else: 261 self.p_lb_FPdiffusion = p_lb_FPdiffusion 262 263 if p_lb_iniDist is None: 264 self.p_lb_iniDist = np.full(len(p0_iniDist), -np.inf) 265 else: 266 self.p_lb_iniDist = p_lb_iniDist 267 268 # upper parameter bounds 269 # set to vectors of np.inf if not given 270 if p_ub_FPdrift is None: 271 self.p_ub_FPdrift = np.full(len(p0_FPdrift), np.inf) 272 else: 273 self.p_ub_FPdrift = p_ub_FPdrift 274 275 if p_ub_FPdiffusion is None: 276 self.p_ub_FPdiffusion = np.full(len(p0_FPdiffusion), np.inf) 277 else: 278 self.p_ub_FPdiffusion = p_ub_FPdiffusion 279 280 if p_ub_iniDist is None: 281 self.p_ub_iniDist = np.full(len(p0_iniDist), np.inf) 282 else: 283 self.p_ub_iniDist = p_ub_iniDist 284 285 # put initials, lower and upper bounds in one vector each 286 self.p0 = np.concatenate((p0_FPdrift, p0_FPdiffusion, p0_iniDist)) 287 self.p_lb = np.concatenate((p_lb_FPdrift, p_lb_FPdiffusion, p_lb_iniDist)) 288 self.p_ub = np.concatenate((p_ub_FPdrift, p_ub_FPdiffusion, p_ub_iniDist)) 289 290 # indices 291 self.idxFPdrift = np.arange(0, len(p0_FPdrift) ) 292 self.idxFPdiffusion = np.arange(0, len(p0_FPdiffusion) ) + len(p0_FPdrift) 293 self.idxFPall = np.arange(0, len(p0_FPdrift)+len(p0_FPdiffusion) ) 294 self.idxIniDist = np.arange(0, len(p0_iniDist) ) + ( len(p0_FPdrift) + len(p0_FPdiffusion) )
328class Grid: 329 """ 330 FPEX0 discretization(?) grid. 331 332 ## Parameters 333 **gridT** 334 <br> x-grid = temperatures 335 <br> This is our method of lines discretization grid. 336 337 **gridTdot** 338 <br> t-grid = heating rates 339 340 **N** 341 <br> Number of grid points. 342 343 **h** 344 <br> Grid size. 345 """ 346 def __init__(self, gridT, gridTdot): 347 self.gridT = gridT 348 self.gridTdot = gridTdot 349 self.N = len(gridT) 350 self.h = ( gridT[-1] - gridT[0] ) / self.N
FPEX0 discretization(?) grid.
Parameters
gridT
x-grid = temperatures
This is our method of lines discretization grid.
gridTdot
t-grid = heating rates
N
Number of grid points.
h
Grid size.
354class Measurements: 355 """ 356 Stores measurement data in list containers. 357 358 ## Parameters 359 **rawT** 360 <br> Measurement temperatures. 361 362 **temperatures** 363 <br> Selected temperatures from temperature grid. 364 365 **rawValues** 366 <br> Raw masurement values. 367 368 **values** 369 <br> rawValues interpolated to grid. 370 371 **rates** 372 <br> Heat rates. 373 374 **ID** 375 <br> Experiment name/identifier. 376 """ 377 def __init__(self, rawT=[], temperatures=[], rawValues=[], values=[], rates=[], ID=[]): 378 self.rawT = rawT 379 self.temperatures = temperatures 380 self.rawValues = rawValues 381 self.rates = rates 382 self.ID = ID 383 self.values = values 384 385 def appendMeasurement(self, new_T, new_temperatures, new_rawValues, new_values, new_rate, new_ID=None): 386 """ 387 Appends given measurements to the measurement parameters. 388 """ 389 self.rawT.append(new_T) 390 self.temperatures.append(new_temperatures) 391 self.rawValues.append(new_rawValues) 392 self.values.append(new_values) 393 self.rates.append(new_rate) 394 self.ID.append(new_ID)
Stores measurement data in list containers.
Parameters
rawT
Measurement temperatures.
temperatures
Selected temperatures from temperature grid.
rawValues
Raw masurement values.
values
rawValues interpolated to grid.
rates
Heat rates.
ID
Experiment name/identifier.
385 def appendMeasurement(self, new_T, new_temperatures, new_rawValues, new_values, new_rate, new_ID=None): 386 """ 387 Appends given measurements to the measurement parameters. 388 """ 389 self.rawT.append(new_T) 390 self.temperatures.append(new_temperatures) 391 self.rawValues.append(new_rawValues) 392 self.values.append(new_values) 393 self.rates.append(new_rate) 394 self.ID.append(new_ID)
Appends given measurements to the measurement parameters.
398class Integration: 399 """ 400 Represents FPEX0 integrator. 401 402 ## Parameters 403 **method** 404 <br> Method to use by scipy solve_ivp. Default is BDF. 405 406 **options** 407 <br> Integration options. Currently not used. 408 409 **integrator** 410 <br> Integrator for ODEs. Should have the signature integrator(FPrhs, t0tf, u0, method). 411 412 **NN, A, B**: Internal variables used by FokkerPlanckODE_dfdu. 413 """ 414 # (TODO) Set default tolerances in Integration class (?) 415 def __init__(self, integrator=solve_ivp, method="BDF", options={}): 416 self.method = method 417 self.options = options 418 self.integrator = integrator 419 self.NN = None # variables for FokkerPlanckODE_dfdu() 420 self.A = None 421 self.B = None 422 423 def updateOptions(self, newOptions): 424 """ Returns the integrators options. """ 425 options = copy(self.options) 426 for key in newOptions: 427 options[key] = newOptions[key] 428 self.options = options 429 return options 430 431 432 def updateJacobian(self, jacobianFcn): 433 """ Returns an option dictionary with updated jacobian. """ 434 options = copy(self.options) 435 options["jac"] = jacobianFcn 436 self.options = options 437 return options
Represents FPEX0 integrator.
Parameters
method
Method to use by scipy solve_ivp. Default is BDF.
options
Integration options. Currently not used.
integrator
Integrator for ODEs. Should have the signature integrator(FPrhs, t0tf, u0, method).
NN, A, B: Internal variables used by FokkerPlanckODE_dfdu.
423 def updateOptions(self, newOptions): 424 """ Returns the integrators options. """ 425 options = copy(self.options) 426 for key in newOptions: 427 options[key] = newOptions[key] 428 self.options = options 429 return options
Returns the integrators options.
432 def updateJacobian(self, jacobianFcn): 433 """ Returns an option dictionary with updated jacobian. """ 434 options = copy(self.options) 435 options["jac"] = jacobianFcn 436 self.options = options 437 return options
Returns an option dictionary with updated jacobian.