geff.bgtypes
This module defines base classes used throughout the GEFF module.
The main purpose of these classes is to address the following. Most quantities appearing in the GEF will scale according to an inverse-time scale, $\omega$, and an energy scale, $\mu$. For example, a time derivative scales with inverse time, $\partial_t \sim \omega$. Consequently, also a gauge field, $A_\mu \sim \omega$, as it appears in covariant derivatives. On the other hand, the amplitude of a scalar field scales with energy, $\varphi \sim \mu$. In typical inflationary contexts, $\omega \equiv H_0$, some constant Hubble rate, and $\mu \equiv M_{\rm P}$, the Planck mass.
For numerical applications, it is convenient to work with dimensionless quantities. For example, it is useful to perform numerical computations using the dimensionless scalar amplitude $\bar{\varphi} = \varphi/\mu$, or the dimensionless gauge field, $\bar{A}_\mu = A_\mu / \omega$. Ultimately, the quantities we are interested in are obviously $\varphi$, $A_\mu$, etc. Therefore, we need an easy way to switch between $\bar{X}$ and $X$.
Throughout the code, we refer to the dimensionless variable, $\bar{X}$, as being in numerical units, while $X$ is in physical units.
To facilitate switching between these two unit systems throughout the code, this module provides the classes BGSystem, Variable, Constant, and Func.
The latter three are collectively referred to as Quantity objects.
Each Quantity object is defined by a scaling with $\omega$ and $\mu$. For example, the Quantity $X$ scales as $X = \omega^a \mu^b \bar{X}$, where $\bar{X}$ is the re-scaled quantity used for numerical computations.
A BGSystem is a collection of Quantity objects, which defines a common unit system by setting the value of $\omega$ and $\mu$.
The user may define variables that evolve with cosmic time using the define_var class factory, which creates subclasses of Variable. Examples of a Variable are the Hubble rate, scalar field amplitude etc.
In the same manner, the user can define constants of cosmic time using the define_const class factory, which creates subclasses of Constant. Examples of a Constant are, e.g., coupling strengths.
Some quantities are functions of variables, for example, a scalar potential. These are defined by the factory define_func, which creates subclasses of Func.
The following examples illustrates the basic use of these classes:
Examples
- Defining a
BGSystem
from GEFF.bgtypes import BGSystem, define_var
# define two variables corresponding to physical time and Hubble rate.
time = define_var("t", qu_omega=-1, qu_mu=0)
Hubble = define_var("H", qu_omega=1, qu_mu=0)
# Create a BGSystem with 'time' and 'Hubble'
# We set the reference frequency to 1e-5*Mpl
# The reference energy is the Planck mass in Planck units (so 1)
U = BGSystem({time, Hubble}, omega=1e-5, mu=1)
# The BGSystem knows about the new variables time and Hubble
print(U.quantity_names()) # prints ["t", "H"]
# However, neither the constant nor the variable are instantiated
# (we did not specify their value)
print(U.variable_names()) # prints []
# Instantiate the quantities t and H using the units defined by U:
U.initialise("t")(1e5)
U.initialise("H")(1e-5)
print(U.variable_names()) # prints ["t", "H"]
# The BGSystem now recognizes "t" and "H" as keys:
print(f"In Planck units, the Hubble rate at time {U.t.value:.1e} is {U.H.value:.1e}.")
# gives U.t=1e5, U.H=1e-5
# Convert everything to numerical units
U.units = False
print(f"In numerical units, the Hubble rate at time {U.t.value} is {U.H.value:.1e}.")
# gives U.t=1, U.H=1
- Adding a new
Variable
#Let us reset the units of U:
U.units = True
# add a new Val: the electric-field expectation value E^2
U.add_variable("E0", qu_omega=4, qu_mu=0) #since A_mu scales like d / dx^mu
# initialise E0 with some value in Planck units:
U.initialise("E0")( 6e-10 )
- Operations between
Variable's
# We add a new Variable to U, the magnetic-field expectation value
U.add_variable("B0", 4, 0)
U.initialise("B0")(1e-10)
# We can safely add up E0 and B0 as they are in the same units:
print(U.E0 + U.B0) #gives 7e-10 = 6e-10 + 1e-10
# This behaviour is not exclusive to Variables,
# but also works for Constants:
U.add_constant("BConst", 4, 0)
U.initialise("BConst")(5e-11)
print(U.E0 + U.BConst) #gives 6.5e-10 = 6e-10 + 5e-11
- Changing the value of a
Variable
# The value of a `Variable` can be passed directly
U.BConst.value = 1e-3
print(str(U.BConst))
# if we change to numerical units,
# the argument which is passed is treated in numerical units
U.units = False
U.BConst.value = 1
print(U.BConst)
- Adding a new
Func
#first, return to physical units
U.units = True
# define a new Func: rhoE, the electric-field energy density
rhoE = U.add_function("rhoE", args=[U.E0], qu_omega=2, qu_mu=2) # since 3 * M_pl^2 * H^2 = rho
#Note how E0 is passed for creation to indicate the scaling of the argument
# define rhoE as a function of E0:
def func(x): return 0.5*x
U.initialise("rhoE")( func )
# U.rhoE is now a Callable function with a single argument
# Calling rhoE in physical units is straight forwards:
print( U.rhoE( U.E0 ) ) # gives 3e-10 (in Planck units)
# compare this to a direct call to func:
print( func(6e-10) ) # gives 3e-10 (the result in Planck units)
# Switching E0 to numerical units, nothing changes since rhoE is in physical units:
U.E0.units = False # E0.value = 6e10
print( U.rhoE(U.E0) ) # gives 3e-10 (still in Planck units)
# Only switching U.rhoE to numerical units changes the result:
U.rhoE.units = False
print( U.rhoE(U.E0) ) # gives 3. = 3e-10 / (U.omega*U.mu)**2 (now in numerical units)
# Again, this outcome does not depend on the units of E0:
U.E0.units = False
print( U.rhoE(U.E0) ) # gives 3. = 3e-10 / (U.omega*U.mu)**2 (in numerical units)
- Calling a
Funcwith afloat
# instead of calling rhoE by E0, we can call it by a float:
val = 6e-10
# First the behavior if rhoE is in physical units:
U.rhoE.units = True
print( U.rhoE( val ) ) # gives 3e-10 (in Planck units)
# The behavior is different compared to a Val if rhoE is in numerical units:
U.rhoE.units = False
print( U.rhoE(val) ) #gives 3e-20 = 0.5* (6e-10*U.omega**4) / (U.omega*U.mu)**2
# Unlike a Val, the float does not track units
# Therefore, it is always assumed to be in the units of rhoE
# If you want to get the correct result, you would need to convert val by hand:
print( U.rhoE(val/U.omega**4) ) # gives 3., the expected result in numerical units.
# Overall, its safer to just keep everything in the same units:
U.units = True
1from ._docs import generate_docs, docs_bgtypes 2import numpy as np 3from typing import Callable, ClassVar 4import pandas as pd 5from copy import deepcopy 6 7class BGSystem: 8 def __init__(self, quantity_set : set, omega : float, mu : float): 9 """ 10 Create a new BGSystem in physical units. 11 12 Parameters 13 ---------- 14 quantity_set : set of Quantity 15 used to define `quantities` 16 omega : float 17 the characteristic frequency scale 18 mu : float 19 the characteristic energy scale 20 """ 21 self.quantities : dict = {q.name:q for q in quantity_set} 22 """A dictionary of all `Quantity` objects for this BGSystem""" 23 self._omega : float = omega 24 self._mu : float = mu 25 self._units=True 26 27 @property 28 def omega(self) -> float: 29 """A frequency scale (typically the Hubble rate at some reference time)""" 30 return self._omega 31 32 @property 33 def mu(self) -> float: 34 """An energy scale (typically the Planck mass)""" 35 return self._mu 36 37 @property 38 def units(self) -> bool: 39 """Indicates the current units of the BGSystem. `True`:physical units, `False`:numerical units""" 40 return self._units 41 42 @units.setter 43 def units(self, newunits:bool): 44 """Change the units of the BGSystem and its `Quantity` instances.""" 45 for var in vars(self): 46 obj = getattr(self, var) 47 if isinstance(obj, Quantity): 48 obj.units = newunits 49 self._units=bool(newunits) 50 return 51 52 53 @classmethod 54 def from_system(cls, sys : 'BGSystem', copy : bool=False) -> 'BGSystem': 55 """Initialize a new `BGSystem` from an existing instance. 56 57 The new instance is created with the same quantities, reference frequency and amplitude as the original. 58 If specified, the `Quantity` instances are also copied to the new BGSystem 59 60 Parameters 61 ---------- 62 sys : BGSystem 63 the original instance used as a template 64 copy : Boolean 65 `True` if `Quantity` instances are also copied 66 Returns 67 ------- 68 newinstance : BGSystem 69 the new instance 70 """ 71 72 newinstance = cls(sys.quantity_set(), sys.omega, sys.mu) 73 74 if copy: 75 #store units of original sys 76 units = sys.units 77 #match units of new system 78 sys.units = True 79 80 #Copy values and functions 81 values = sys.variable_list() 82 funcs = sys.function_list() 83 consts = sys.constant_list() 84 85 for const in consts: 86 obj = const 87 newinstance.initialise(obj.name)(obj.value) 88 89 for value in values: 90 obj = value 91 newinstance.initialise(obj.name)(obj.value) 92 93 for func in funcs: 94 obj = func 95 newinstance.initialise(obj.name)(obj.basefunc) 96 97 #restore old units 98 sys.units = units 99 100 return newinstance 101 102 def quantity_set(self) -> set[object]: 103 """ 104 Get a set of all `Quantity` objects attributed to this BGSystem. 105 106 Returns 107 ------- 108 set : set 109 a set of objects. 110 """ 111 112 return set(self.quantities.values()) 113 114 def quantity_names(self) -> list[str]: 115 """ 116 Get a list of names for all `Quantity` objects attributed to this BGSystem. 117 118 Returns 119 ------- 120 names : list of str 121 the list of names. 122 """ 123 124 return list(self.quantities.keys()) 125 126 127 def initialise(self, quantity : str) -> Callable: 128 """ 129 Instantiate a `Quantity` object from `quantities`. 130 131 The method creates a function `init` which can be called by 132 an arithmetic type / `Callable` to instantiate a `Val` / `Func`. 133 Calling `init` adds and instance of the `Quantity` as a new attribute to the BGSystem, 134 with the attribute name corresponding to the object's `name` attribute. 135 136 Parameters 137 ---------- 138 quantity : str 139 the name of the object which is to be instantiated. 140 141 Returns 142 ------- 143 init : Callable 144 a function used to initialize the `Quantity` object 145 """ 146 147 def init(obj : np.ndarray | Callable): 148 """ 149 Initialize a `Quantity` object with an arithmetic type / Callable. 150 151 This adds an instance of the `Quantity` as a new attribute to the `BGSystem`, with the attribute name 152 corresponding to the `Quantity` object's `name` attribute. 153 154 Parameters 155 ---------- 156 obj : NDArray or Callable 157 the NDArray / Callable with which the `Quantity` is to be instantiated. 158 """ 159 160 q = self.quantities[quantity] 161 setattr( self, quantity, q(obj, self) ) 162 return 163 164 return init 165 166 def variable_list(self) -> list['Variable']: 167 """ 168 Get a list of all `Variable` instances attributed to this BGSystem. 169 170 Returns 171 ------- 172 vals : list of Variable 173 the list of `Variable` instances. 174 """ 175 176 vals = [] 177 for var in vars(self): 178 obj = getattr(self, var) 179 if isinstance(obj, Variable): 180 vals.append(obj) 181 return vals 182 183 def variable_names(self) -> list[str]: 184 """ 185 Get a list of names for all `Variable` instances attributed to this BGSystem. 186 187 Returns 188 ------- 189 names : list of str 190 the list of names. 191 """ 192 193 names = [] 194 for val in self.variable_list(): 195 names.append(val.name) 196 return names 197 198 def constant_list(self) -> list['Constant']: 199 """ 200 Get a list of all `Constant` instances attributed to this BGSystem. 201 202 Returns 203 ------- 204 vals : list of Val 205 the list of `Constant` instances. 206 """ 207 208 vals = [] 209 for var in vars(self): 210 obj = getattr(self, var) 211 if isinstance(obj, Constant): 212 vals.append(obj) 213 return vals 214 215 def constant_names(self) -> list[str]: 216 """ 217 Get a list of names for all `Constant` instances attributed to this BGSystem. 218 219 Returns 220 ------- 221 names : list of str 222 the list of names. 223 """ 224 225 names = [] 226 for val in self.constant_list(): 227 names.append(val.name) 228 return names 229 230 def function_list(self) -> list['Func']: 231 """ 232 Get a list of all `Func` instances attributed to this BGSystem. 233 234 Returns 235 ------- 236 funcs : list of Func 237 the list of `Func` instances. 238 """ 239 240 funcs = [] 241 for var in vars(self): 242 obj = getattr(self, var) 243 if isinstance(obj, Func): 244 funcs.append(obj) 245 return funcs 246 247 def function_names(self) -> list[str]: 248 """ 249 Get a list of names for all `Func` instances attributed to this BGSystem. 250 251 Returns 252 ------- 253 names : list of str 254 the list of names. 255 """ 256 257 names = [] 258 for val in self.function_list(): 259 names.append(val.name) 260 return names 261 262 def remove(self, name : str): 263 """ 264 Remove a `Quantity` object and its instance from the BGSystem. 265 266 Parameters 267 ---------- 268 name : str 269 the name of the object 270 """ 271 272 delattr(self, name) 273 self.quantities.pop(name) 274 return 275 276 def add_variable(self, name : str, qu_omega : int, qu_mu : int): 277 """ 278 Define a new `Variable` object and add it to `quantities`. 279 280 Parameters 281 ---------- 282 name : str 283 the name of the new object. 284 qu_omega : int 285 the 'u_omega' parameter of the new object. 286 qu_mu : int 287 the 'u_mu' parameter of the new object. 288 """ 289 290 self.quantities[name] = define_var(name, qu_omega, qu_mu) 291 return 292 293 def add_constant(self, name : str, qu_omega : int, qu_mu : int): 294 """ 295 Define a new `Constant` object and add it to `quantities`. 296 297 Parameters 298 ---------- 299 name : str 300 the name of the new object. 301 qu_omega : int 302 the 'u_omega' parameter of the new object. 303 qu_mu : int 304 the 'u_mu' parameter of the new object. 305 """ 306 307 self.quantities[name] = define_const(name, qu_omega, qu_mu) 308 return 309 310 def add_function(self, name : str, args : list['Val'], qu_omega : int, qu_mu : int): 311 """ 312 Define a new `Func` object and add it to `quantities`. 313 314 Parameters 315 ---------- 316 name : str 317 the name of the new object. 318 args : list of BGVal 319 the 'args' parameter of the new object. 320 qu_omega : int 321 the 'u_omega' parameter of the new object. 322 qu_mu : int 323 the 'u_mu' parameter of the new object. 324 """ 325 326 self.quantities[name] = define_func(name, args, qu_omega, qu_mu) 327 return 328 329 def save_variables(self, path : str): 330 """ 331 Save the data in the current GEF instance in an output file. 332 333 Note, data is always stored in numerical units. 334 The save will not store constants or functions, only variables. 335 336 Parameters 337 ---------- 338 path : str 339 Path to store data in. 340 341 Raises 342 ------ 343 ValueError 344 if the GEF object has no data to store. 345 """ 346 347 storeables = self.variable_names() 348 #Check that all dynamic and derived quantities are initialised in this GEF instance 349 if len(storeables) == 0: 350 raise ValueError("No data to store.") 351 352 #Create a dictionary used to initialise the pandas DataFrame 353 dic = {} 354 355 #remember the original units of the GEF 356 og_units=self.units 357 358 #Data is always stored unitless 359 self.units = False 360 361 for key in storeables: 362 dic[key] = getattr(self, key).value 363 364 #Create pandas data frame and store the dictionary under the user-specified path 365 output_df = pd.DataFrame(dic) 366 output_df.to_csv(path) 367 368 #after storing data, restore original units 369 self.units = og_units 370 return 371 372 def load_variables(self, path : str): 373 """ 374 Load data and store its results in the BGSystem. 375 376 Note, data is always loaded assuming numerical units. 377 Data is only loaded for variables, not for functions or constants. 378 379 Parameters 380 ---------- 381 path : None or str 382 Path to load data from 383 384 Raises 385 ------ 386 FileNotFoundError 387 if no file is found at `path`. 388 AttributeError 389 if the file contains a column labeled by a key which does not match any BGSystem variable. 390 """ 391 #Check if file exists 392 try: 393 #Load from file 394 input_df = pd.read_table(path, sep=",") 395 except FileNotFoundError: 396 raise FileNotFoundError(f"No file found under '{path}'") 397 398 #Dictionary for easy access using keys 399 400 data = dict(zip(input_df.columns[1:],input_df.values[:,1:].T)) 401 402 #Before starting to load, check that the file is compatible with the GEF setup. 403 names = self.quantity_names() 404 for key in data.keys(): 405 if key not in names: 406 raise AttributeError(f"The data table you tried to load contains an unknown quantity: '{key}'") 407 408 #Store current units to switch back to later 409 og_units=self.units 410 411 #GEF data is always stored untiless, thus it is assumed to be untiless when loaded. 412 self.units = False 413 #Load data into background-value attributes 414 for key, values in data.items(): 415 if key in self.variable_names(): 416 getattr(self, key).value = values 417 else: 418 self.initialise(key)(values) 419 420 self.units = og_units 421 return 422 423 424class Quantity: 425 name : ClassVar[str]= "" 426 """The objects name""" 427 description : ClassVar[str]= "" 428 """A brief description of the object""" 429 u_omega : ClassVar[int] = 0 430 """Indicates how the object scales with frequency.""" 431 u_mu : ClassVar[int] = 0 432 """Indicates how the object scales with energy.""" 433 434 def __init__(self, sys : BGSystem): 435 """ 436 Create a new Quantity as part of a BGSystem 437 438 The units of the new object matches those of the BGSystem 439 440 Parameters 441 ---------- 442 sys : BGSystem 443 the BGSystem to which the object belongs 444 """ 445 446 self._units = sys.units 447 self._conversion = (sys.omega**self.u_omega*sys.mu**self.u_mu) 448 449 def __repr__(self): 450 r"""A string representing the class, giving its name and scaling with frequency ($\omega$) and energy ($\mu$).""" 451 return f"{self.name}({self.u_omega},{self.u_mu})" 452 453 def __str__(self) -> str: 454 """The class instance as a string including its name and current units.""" 455 456 if not(self._units): 457 return f"{self.name} (numerical)" 458 elif self._units: 459 return f"{self.name} (physical)" 460 461 462 @property 463 def units(self) -> bool: 464 """Indicates the current units of the Quantity. `True`:physical units, `False`:numerical units""" 465 return self._units 466 467 @units.setter 468 def units(self, units : bool): 469 """Convert the object between numerical and physical units.""" 470 self._units = bool(units) 471 return 472 473 @property 474 def conversion(self) -> float: 475 """A conversion factor between numerical and physical units.""" 476 return self._conversion 477 478 @classmethod 479 def get_description(cls) -> str: 480 """Return a string describing the object.""" 481 if cls.description=="": 482 return f"{cls.name}" 483 else: 484 return f"{cls.name} - {cls.description}" 485 486 487 488class Val(Quantity): 489 def __init__(self, value : np.ndarray|float, sys : BGSystem): 490 """ 491 Create a new instance using a BGSystem. 492 493 Parameters 494 ---------- 495 value : NDArray 496 the underlying array of the instance 497 sys : BGSystem 498 the BGSystem to which the instance belongs 499 """ 500 super().__init__(sys) 501 self._value = value*self._conversion**(-sys.units) 502 503 def __str__(self) -> str: 504 """ 505 The class instance as a string including its name, current units, and its value. 506 507 Returns 508 ------- 509 str 510 the string representation. 511 """ 512 513 if not(self._units): 514 return f"{self.name} (numerical): {self.value}" 515 elif self._units: 516 return f"{self.name} (physical): {self.value}" 517 518 @property 519 def value(self) -> float: 520 """The objects value in its respective units.""" 521 return self._value*self._conversion**self._units 522 523 @value.setter 524 def value(self, newval): 525 """Overwrite the `value` attribute (assuming its current units).""" 526 self._value = newval*self._conversion**(-self._units) 527 return 528 529 #Define all mathematical operations as operations acting on self.value 530 def __abs__(self): 531 return abs(self.value) 532 533 def __neg__(self): 534 return -self.value 535 536 def __pos__(self): 537 return +self.value 538 539 def __add__(self, other): 540 #self.__Compatible(self, other, "+") 541 return self.value + other 542 543 __radd__ = __add__ 544 545 def __sub__(self, other): 546 #self.__Compatible(self, other, "-") 547 return self.value - other 548 549 def __rsub__(self, other): 550 return other - self.value 551 552 def __mul__(self, other): 553 return self.value * other 554 555 __rmul__ = __mul__ 556 557 def __floordiv__(self, other): 558 return self.value // other 559 560 def __rfloordiv__(self, other): 561 return other // self.value 562 563 def __truediv__(self, other): 564 return self.value / other 565 566 def __rtruediv__(self, other): 567 return other / self.value 568 569 def __mod__(self, other): 570 return self.value % other 571 572 def __pow__(self, other): 573 #BGVal should never be exponentiated by another BGVal 574 return self.value ** other 575 576 def __eq__(self, other): 577 #self.__Compatible(self, other, "==") 578 return self.value == other 579 580 def __ne__(self, other): 581 #self.__Compatible(self, other, "!=") 582 return self.value != other 583 584 def __lt__(self, other): 585 #self.__Compatible(self, other, "<") 586 return self.value < other 587 588 def __gt__(self, other): 589 #self.__Compatible(self, other, ">") 590 return self.value > other 591 592 def __le__(self, other): 593 #self.__Compatible(self, other, "<=") 594 return self.value <= other 595 596 def __ge__(self, other): 597 #self.__Compatible(self, other, ">=") 598 return self.value >= other 599 600 601class Func(Quantity): 602 args : ClassVar[list[Val]] = [] 603 """Indicates the argument signature for the class.""" 604 dtype : ClassVar[np.floating] = np.float64 605 """The data type returned by `__call__`.""" 606 607 def __init__(self, func : Callable, sys : BGSystem): 608 """ 609 Create a new instance using a `Callable` and a BGSystem 610 611 Parameters 612 ---------- 613 func : NDArray 614 the underlying function `f(*args)` of the instance 615 sys : BGSystem 616 the BGSystem to which the instance belongs 617 618 Raises 619 ------ 620 TypeError 621 if the number of arguments of `func` do not match `args` 622 ValueError 623 if the return of`func` can't be converted to `dtype` 624 """ 625 super().__init__(sys) 626 func = np.vectorize(func, otypes=[self.dtype]) 627 628 try: 629 testargs = [1.0 for arg in self.args] 630 assert func(*testargs).dtype 631 except TypeError: 632 raise TypeError("The number of non-default arguments of 'func' needs to match 'len(self.args)'.") 633 except ValueError: 634 raise ValueError(f"'func' must return a single value which can be converted to '{self.dtype}'") 635 636 self._basefunc = func 637 638 self._arg_conversions = [(sys.omega**arg.u_omega*sys.mu**arg.u_mu) 639 for arg in self.args] 640 641 @property 642 def basefunc(self) -> Callable: 643 """The underlying function which defines the `__call__` method.""" 644 return self._basefunc 645 646 def get_arg_conversions(self) -> list[float]: 647 """ 648 Get a list of conversion factors for each argument of `basefunc`. 649 650 Returns 651 ------- 652 arg_conversions : list of float 653 a list of conversion factors 654 """ 655 656 return self._arg_conversions 657 658 def __call__(self, *args): 659 """ 660 Define the call method of the class as outlined in its documentation. 661 """ 662 def float_handler(x, i): 663 return x*self._arg_conversions[i]**(1-self._units) 664 665 def val_handler(x, i): 666 conv = x.conversion 667 assert self._arg_conversions[i] == conv 668 return x*conv**(1-x.units) 669 670 typedic = {Variable : val_handler, Val : val_handler, Constant: val_handler} 671 672 args = [typedic.get(arg.__class__.__bases__[0], float_handler)(arg, i) for i, arg in enumerate(args)] 673 674 return self._basefunc(*args)/self._conversion**(1-self._units) 675 676 677class Variable(Val): 678 dtype : ClassVar[np.floating] = np.float64 679 """The data type of `value`.""" 680 681 def __init__(self, value : np.ndarray, sys : BGSystem): 682 """ 683 Create a new instance using a numpy array and a BGSystem 684 685 Parameters 686 ---------- 687 value : NDArray 688 the underlying array of the instance 689 sys : BGSystem 690 the BGSystem to which the instance belongs 691 """ 692 super().__init__( np.asarray(value, dtype=self.dtype), sys) 693 694 #The following methods ensure that a `Val` instance can be used as an array concerning mathematical operations and indexing. 695 696 def __getitem__(self, idx): 697 return self.value[idx] 698 699 def __len__(self): 700 return len(self.value) 701 702 @property 703 def value(self) -> np.ndarray: 704 """The objects value in its respective units.""" 705 return self._value*self._conversion**(self._units) 706 707 @value.setter 708 def value(self, newval): 709 """Overwrite the `value` attribute ensuring it is an array""" 710 self._value = np.asarray(newval*self._conversion**(-self._units), dtype=self.dtype) 711 return 712 713class Constant(Val): 714 def __init__(self, value, sys : BGSystem): 715 """ 716 Create a new instance using a float and a BGSystem 717 718 Parameters 719 ---------- 720 value : NDArray 721 the underlying array of the instance 722 sys : BGSystem 723 the BGSystem to which the instance belongs 724 725 Raises 726 ------ 727 TypeError 728 if value cannot be converted to a float 729 """ 730 super().__init__( float(value), sys) 731 732class GaugeField: 733 name : ClassVar[str] = "" 734 """The name of the class.""" 735 zeros : ClassVar[list[Variable]]= [] 736 r"""A list of the associated 0$^{\rm th}$ order quantities.""" 737 cutoff : Variable = None 738 """The associated UV cutoff scale.""" 739 740 @classmethod 741 def get_description(cls) -> str: 742 """Return a string describing the object.""" 743 return f"{cls.name} - associated with: {[a.name for a in cls.zeros]}, UV cutoff: {cls.cutoff.name}" 744 745def define_var(qname : str, qu_omega : int, qu_mu : int, qdescription:str="", qdtype : np.dtype=np.float64): 746 """ 747 Creates a subclass of `Variable` with custom name, and scaling. 748 749 Parameters 750 ---------- 751 qname : str 752 the `name` attribute of the subclass 753 qu_omega : int 754 the `u_omega` attribute of the subclass 755 qu_mu : int 756 the `u_mu` attribute of the subclass 757 qdescription : str 758 a brief description of the subclass 759 qdtype : Numpy Data Type 760 the `dtype` attribute of the subclass 761 762 763 Returns 764 ------- 765 CustomVar : class 766 the custom subclass 767 768 Raises 769 ------ 770 TypeError 771 if the data type is not a subtype of `numpy.floating` 772 """ 773 774 if not( np.issubdtype(qdtype, np.floating) ): 775 raise TypeError("BGVal's data-type must be a subtype of 'numpy.floating'.") 776 777 class CustomVar(Variable): 778 __doc__ = docs_bgtypes.DOCS["define_var.CustomVar"] 779 name=qname 780 u_omega = qu_omega 781 u_mu = qu_mu 782 dtype = qdtype 783 description = qdescription 784 def __init__(self, value, sys): 785 super().__init__(value, sys) 786 CustomVar.__qualname__ = f"Val_{qname}" 787 CustomVar.__module__ = __name__ 788 789 return CustomVar 790 791def define_const(qname : str, qu_omega : int, qu_mu : int, qdescription:str=""): 792 """ 793 Creates a subclass of `Constant` with custom name, and scaling. 794 795 Parameters 796 ---------- 797 qname : str 798 the `name` attribute of the subclass 799 qu_omega : int 800 the `u_omega` attribute of the subclass 801 qu_mu : int 802 the `u_mu` attribute of the subclass 803 qdescription : str 804 a brief description of the subclass 805 806 Returns 807 ------- 808 CustomConst : class 809 the custom subclass 810 """ 811 812 class CustomConst(Constant): 813 __doc__ = docs_bgtypes.DOCS["define_const.CustomConst"] 814 name=qname 815 u_omega = qu_omega 816 u_mu = qu_mu 817 description = qdescription 818 def __init__(self, value, sys): 819 super().__init__(value, sys) 820 CustomConst.__qualname__ = f"Const_{qname}" 821 CustomConst.__module__ = __name__ 822 823 return CustomConst 824 825 826 827def define_func(qname : str, func_args : list[Val], qu_omega : int, qu_mu : int, qdescription:str="", qdtype : np.dtype=np.float64): 828 """ 829 Creates a subclass of `Func` with custom name, scaling, and argument signature. 830 831 Parameters 832 ---------- 833 qname : str 834 the `name` attribute of the subclass 835 qu_omega : int 836 the `u_omega` attribute of the subclass 837 qu_mu : int 838 the `u_mu` attribute of the subclass 839 qdtype : Numpy Data Type 840 the `dtype` attribute of the subclass 841 qdescription : str 842 a brief description of the subclass 843 844 Returns 845 ------- 846 CustomFunc : class 847 the custom subclass 848 849 Raises 850 ------ 851 TypeError 852 if the data type is not a subtype of `numpy.floating` 853 """ 854 855 if not( np.issubdtype(qdtype, np.floating) ): 856 raise TypeError("define_func's data-type must be a subtype of 'np.floating'.") 857 858 class CustomFunc(Func): 859 __doc__ = docs_bgtypes.DOCS["define_func.CustomFunc"] 860 name=qname 861 u_omega = qu_omega 862 u_mu = qu_mu 863 args = func_args 864 dtype = qdtype 865 description = qdescription 866 def __init__(self, func, sys): 867 super().__init__(func, sys) 868 869 CustomFunc.__qualname__ = f"Func_{qname}" 870 CustomFunc.__module__ = __name__ 871 872 return CustomFunc 873 874def define_gauge(qname : str, qzeros : list[Variable], qcutoff : Variable): 875 """ 876 A class factory creating custom `GaugeField` classes with new name, zero variables, and cutoff scale. 877 878 Parameters 879 ---------- 880 qname : str 881 the `name` attribute of the subclass 882 qzeros : list of Variable 883 the `zeros` attribute of the new subclass 884 qcutoff : Variable 885 the `cutoff` attribute of the new subclass 886 887 Returns 888 ------- 889 CustomGaugeField : class 890 the custom subclass 891 """ 892 class CustomGaugeField(GaugeField): 893 name = qname 894 zeros = qzeros 895 cutoff = qcutoff 896 897 CustomGaugeField.__qualname__ = f"GaugeField_{qname}" 898 CustomGaugeField.__module__ = __name__ 899 return CustomGaugeField 900 901#Add docstrings 902generate_docs(docs_bgtypes.DOCS) 903 904#Some usful pre-defined quantities 905#Space--time variables: 906t=define_var("t", -1, 0, "cosmic time") 907N=define_var("N", 0, 0, "e-folds") 908a=define_var("a", 0, 0, "scale factor") 909H=define_var("H", 1, 0, "Hubble rate") 910 911#Inflaton variables: 912phi=define_var("phi", 0, 1, "inflaton expectation value") 913dphi=define_var("dphi", 1, 1, "inflaton velocity") 914ddphi=define_var("ddphi", 2, 1, "inflaton acceleration") 915 916#Inflaton potential 917V=define_func("V", [phi], 2, 2, "scalar potential") 918dV=define_func("dV", [phi], 2, 2, "scalar-potential derivative") 919 920#Gauge-field variables: 921E=define_var("E", 4, 0, "electric-field expectation value, E^2") 922B=define_var("B", 4, 0, "magnetic-field expectation value, B^2") 923G=define_var("G", 4, 0, "Chern-Pontryagin expectation value, -E.B") 924 925#Auxiliary quantities: 926xi=define_var("xi", 0, 0, "instability parameter") 927kh=define_var("kh", 1, 0, "instability scale") 928 929#constants 930beta=define_const("beta", 0, -1, "inflaton--gauge-field coupling beta/Mp") 931 932#basic gauge-field 933GF = define_gauge("GF", [E, B, G], kh)
8class BGSystem: 9 def __init__(self, quantity_set : set, omega : float, mu : float): 10 """ 11 Create a new BGSystem in physical units. 12 13 Parameters 14 ---------- 15 quantity_set : set of Quantity 16 used to define `quantities` 17 omega : float 18 the characteristic frequency scale 19 mu : float 20 the characteristic energy scale 21 """ 22 self.quantities : dict = {q.name:q for q in quantity_set} 23 """A dictionary of all `Quantity` objects for this BGSystem""" 24 self._omega : float = omega 25 self._mu : float = mu 26 self._units=True 27 28 @property 29 def omega(self) -> float: 30 """A frequency scale (typically the Hubble rate at some reference time)""" 31 return self._omega 32 33 @property 34 def mu(self) -> float: 35 """An energy scale (typically the Planck mass)""" 36 return self._mu 37 38 @property 39 def units(self) -> bool: 40 """Indicates the current units of the BGSystem. `True`:physical units, `False`:numerical units""" 41 return self._units 42 43 @units.setter 44 def units(self, newunits:bool): 45 """Change the units of the BGSystem and its `Quantity` instances.""" 46 for var in vars(self): 47 obj = getattr(self, var) 48 if isinstance(obj, Quantity): 49 obj.units = newunits 50 self._units=bool(newunits) 51 return 52 53 54 @classmethod 55 def from_system(cls, sys : 'BGSystem', copy : bool=False) -> 'BGSystem': 56 """Initialize a new `BGSystem` from an existing instance. 57 58 The new instance is created with the same quantities, reference frequency and amplitude as the original. 59 If specified, the `Quantity` instances are also copied to the new BGSystem 60 61 Parameters 62 ---------- 63 sys : BGSystem 64 the original instance used as a template 65 copy : Boolean 66 `True` if `Quantity` instances are also copied 67 Returns 68 ------- 69 newinstance : BGSystem 70 the new instance 71 """ 72 73 newinstance = cls(sys.quantity_set(), sys.omega, sys.mu) 74 75 if copy: 76 #store units of original sys 77 units = sys.units 78 #match units of new system 79 sys.units = True 80 81 #Copy values and functions 82 values = sys.variable_list() 83 funcs = sys.function_list() 84 consts = sys.constant_list() 85 86 for const in consts: 87 obj = const 88 newinstance.initialise(obj.name)(obj.value) 89 90 for value in values: 91 obj = value 92 newinstance.initialise(obj.name)(obj.value) 93 94 for func in funcs: 95 obj = func 96 newinstance.initialise(obj.name)(obj.basefunc) 97 98 #restore old units 99 sys.units = units 100 101 return newinstance 102 103 def quantity_set(self) -> set[object]: 104 """ 105 Get a set of all `Quantity` objects attributed to this BGSystem. 106 107 Returns 108 ------- 109 set : set 110 a set of objects. 111 """ 112 113 return set(self.quantities.values()) 114 115 def quantity_names(self) -> list[str]: 116 """ 117 Get a list of names for all `Quantity` objects attributed to this BGSystem. 118 119 Returns 120 ------- 121 names : list of str 122 the list of names. 123 """ 124 125 return list(self.quantities.keys()) 126 127 128 def initialise(self, quantity : str) -> Callable: 129 """ 130 Instantiate a `Quantity` object from `quantities`. 131 132 The method creates a function `init` which can be called by 133 an arithmetic type / `Callable` to instantiate a `Val` / `Func`. 134 Calling `init` adds and instance of the `Quantity` as a new attribute to the BGSystem, 135 with the attribute name corresponding to the object's `name` attribute. 136 137 Parameters 138 ---------- 139 quantity : str 140 the name of the object which is to be instantiated. 141 142 Returns 143 ------- 144 init : Callable 145 a function used to initialize the `Quantity` object 146 """ 147 148 def init(obj : np.ndarray | Callable): 149 """ 150 Initialize a `Quantity` object with an arithmetic type / Callable. 151 152 This adds an instance of the `Quantity` as a new attribute to the `BGSystem`, with the attribute name 153 corresponding to the `Quantity` object's `name` attribute. 154 155 Parameters 156 ---------- 157 obj : NDArray or Callable 158 the NDArray / Callable with which the `Quantity` is to be instantiated. 159 """ 160 161 q = self.quantities[quantity] 162 setattr( self, quantity, q(obj, self) ) 163 return 164 165 return init 166 167 def variable_list(self) -> list['Variable']: 168 """ 169 Get a list of all `Variable` instances attributed to this BGSystem. 170 171 Returns 172 ------- 173 vals : list of Variable 174 the list of `Variable` instances. 175 """ 176 177 vals = [] 178 for var in vars(self): 179 obj = getattr(self, var) 180 if isinstance(obj, Variable): 181 vals.append(obj) 182 return vals 183 184 def variable_names(self) -> list[str]: 185 """ 186 Get a list of names for all `Variable` instances attributed to this BGSystem. 187 188 Returns 189 ------- 190 names : list of str 191 the list of names. 192 """ 193 194 names = [] 195 for val in self.variable_list(): 196 names.append(val.name) 197 return names 198 199 def constant_list(self) -> list['Constant']: 200 """ 201 Get a list of all `Constant` instances attributed to this BGSystem. 202 203 Returns 204 ------- 205 vals : list of Val 206 the list of `Constant` instances. 207 """ 208 209 vals = [] 210 for var in vars(self): 211 obj = getattr(self, var) 212 if isinstance(obj, Constant): 213 vals.append(obj) 214 return vals 215 216 def constant_names(self) -> list[str]: 217 """ 218 Get a list of names for all `Constant` instances attributed to this BGSystem. 219 220 Returns 221 ------- 222 names : list of str 223 the list of names. 224 """ 225 226 names = [] 227 for val in self.constant_list(): 228 names.append(val.name) 229 return names 230 231 def function_list(self) -> list['Func']: 232 """ 233 Get a list of all `Func` instances attributed to this BGSystem. 234 235 Returns 236 ------- 237 funcs : list of Func 238 the list of `Func` instances. 239 """ 240 241 funcs = [] 242 for var in vars(self): 243 obj = getattr(self, var) 244 if isinstance(obj, Func): 245 funcs.append(obj) 246 return funcs 247 248 def function_names(self) -> list[str]: 249 """ 250 Get a list of names for all `Func` instances attributed to this BGSystem. 251 252 Returns 253 ------- 254 names : list of str 255 the list of names. 256 """ 257 258 names = [] 259 for val in self.function_list(): 260 names.append(val.name) 261 return names 262 263 def remove(self, name : str): 264 """ 265 Remove a `Quantity` object and its instance from the BGSystem. 266 267 Parameters 268 ---------- 269 name : str 270 the name of the object 271 """ 272 273 delattr(self, name) 274 self.quantities.pop(name) 275 return 276 277 def add_variable(self, name : str, qu_omega : int, qu_mu : int): 278 """ 279 Define a new `Variable` object and add it to `quantities`. 280 281 Parameters 282 ---------- 283 name : str 284 the name of the new object. 285 qu_omega : int 286 the 'u_omega' parameter of the new object. 287 qu_mu : int 288 the 'u_mu' parameter of the new object. 289 """ 290 291 self.quantities[name] = define_var(name, qu_omega, qu_mu) 292 return 293 294 def add_constant(self, name : str, qu_omega : int, qu_mu : int): 295 """ 296 Define a new `Constant` object and add it to `quantities`. 297 298 Parameters 299 ---------- 300 name : str 301 the name of the new object. 302 qu_omega : int 303 the 'u_omega' parameter of the new object. 304 qu_mu : int 305 the 'u_mu' parameter of the new object. 306 """ 307 308 self.quantities[name] = define_const(name, qu_omega, qu_mu) 309 return 310 311 def add_function(self, name : str, args : list['Val'], qu_omega : int, qu_mu : int): 312 """ 313 Define a new `Func` object and add it to `quantities`. 314 315 Parameters 316 ---------- 317 name : str 318 the name of the new object. 319 args : list of BGVal 320 the 'args' parameter of the new object. 321 qu_omega : int 322 the 'u_omega' parameter of the new object. 323 qu_mu : int 324 the 'u_mu' parameter of the new object. 325 """ 326 327 self.quantities[name] = define_func(name, args, qu_omega, qu_mu) 328 return 329 330 def save_variables(self, path : str): 331 """ 332 Save the data in the current GEF instance in an output file. 333 334 Note, data is always stored in numerical units. 335 The save will not store constants or functions, only variables. 336 337 Parameters 338 ---------- 339 path : str 340 Path to store data in. 341 342 Raises 343 ------ 344 ValueError 345 if the GEF object has no data to store. 346 """ 347 348 storeables = self.variable_names() 349 #Check that all dynamic and derived quantities are initialised in this GEF instance 350 if len(storeables) == 0: 351 raise ValueError("No data to store.") 352 353 #Create a dictionary used to initialise the pandas DataFrame 354 dic = {} 355 356 #remember the original units of the GEF 357 og_units=self.units 358 359 #Data is always stored unitless 360 self.units = False 361 362 for key in storeables: 363 dic[key] = getattr(self, key).value 364 365 #Create pandas data frame and store the dictionary under the user-specified path 366 output_df = pd.DataFrame(dic) 367 output_df.to_csv(path) 368 369 #after storing data, restore original units 370 self.units = og_units 371 return 372 373 def load_variables(self, path : str): 374 """ 375 Load data and store its results in the BGSystem. 376 377 Note, data is always loaded assuming numerical units. 378 Data is only loaded for variables, not for functions or constants. 379 380 Parameters 381 ---------- 382 path : None or str 383 Path to load data from 384 385 Raises 386 ------ 387 FileNotFoundError 388 if no file is found at `path`. 389 AttributeError 390 if the file contains a column labeled by a key which does not match any BGSystem variable. 391 """ 392 #Check if file exists 393 try: 394 #Load from file 395 input_df = pd.read_table(path, sep=",") 396 except FileNotFoundError: 397 raise FileNotFoundError(f"No file found under '{path}'") 398 399 #Dictionary for easy access using keys 400 401 data = dict(zip(input_df.columns[1:],input_df.values[:,1:].T)) 402 403 #Before starting to load, check that the file is compatible with the GEF setup. 404 names = self.quantity_names() 405 for key in data.keys(): 406 if key not in names: 407 raise AttributeError(f"The data table you tried to load contains an unknown quantity: '{key}'") 408 409 #Store current units to switch back to later 410 og_units=self.units 411 412 #GEF data is always stored untiless, thus it is assumed to be untiless when loaded. 413 self.units = False 414 #Load data into background-value attributes 415 for key, values in data.items(): 416 if key in self.variable_names(): 417 getattr(self, key).value = values 418 else: 419 self.initialise(key)(values) 420 421 self.units = og_units 422 return
A collection of cosmological variables sharing a system of units.
Instances of this class define two base unit systems,
physical units and numerical units, by setting an energy scale, mu, and an inverse time scale, omega.
The cosmological variables (time, Hubble rate, etc.) are represented by Quantity objects.
These objects are stored in quantities, and can can be initialise using initialise.
Instances of these objects can be collectively converted between units by setting units.
This class is the fundamental building block of the GEFF code.
9 def __init__(self, quantity_set : set, omega : float, mu : float): 10 """ 11 Create a new BGSystem in physical units. 12 13 Parameters 14 ---------- 15 quantity_set : set of Quantity 16 used to define `quantities` 17 omega : float 18 the characteristic frequency scale 19 mu : float 20 the characteristic energy scale 21 """ 22 self.quantities : dict = {q.name:q for q in quantity_set} 23 """A dictionary of all `Quantity` objects for this BGSystem""" 24 self._omega : float = omega 25 self._mu : float = mu 26 self._units=True
Create a new BGSystem in physical units.
Parameters
- quantity_set (set of Quantity):
used to define
quantities - omega (float): the characteristic frequency scale
- mu (float): the characteristic energy scale
28 @property 29 def omega(self) -> float: 30 """A frequency scale (typically the Hubble rate at some reference time)""" 31 return self._omega
A frequency scale (typically the Hubble rate at some reference time)
33 @property 34 def mu(self) -> float: 35 """An energy scale (typically the Planck mass)""" 36 return self._mu
An energy scale (typically the Planck mass)
38 @property 39 def units(self) -> bool: 40 """Indicates the current units of the BGSystem. `True`:physical units, `False`:numerical units""" 41 return self._units
Indicates the current units of the BGSystem. True:physical units, False:numerical units
54 @classmethod 55 def from_system(cls, sys : 'BGSystem', copy : bool=False) -> 'BGSystem': 56 """Initialize a new `BGSystem` from an existing instance. 57 58 The new instance is created with the same quantities, reference frequency and amplitude as the original. 59 If specified, the `Quantity` instances are also copied to the new BGSystem 60 61 Parameters 62 ---------- 63 sys : BGSystem 64 the original instance used as a template 65 copy : Boolean 66 `True` if `Quantity` instances are also copied 67 Returns 68 ------- 69 newinstance : BGSystem 70 the new instance 71 """ 72 73 newinstance = cls(sys.quantity_set(), sys.omega, sys.mu) 74 75 if copy: 76 #store units of original sys 77 units = sys.units 78 #match units of new system 79 sys.units = True 80 81 #Copy values and functions 82 values = sys.variable_list() 83 funcs = sys.function_list() 84 consts = sys.constant_list() 85 86 for const in consts: 87 obj = const 88 newinstance.initialise(obj.name)(obj.value) 89 90 for value in values: 91 obj = value 92 newinstance.initialise(obj.name)(obj.value) 93 94 for func in funcs: 95 obj = func 96 newinstance.initialise(obj.name)(obj.basefunc) 97 98 #restore old units 99 sys.units = units 100 101 return newinstance
Initialize a new BGSystem from an existing instance.
The new instance is created with the same quantities, reference frequency and amplitude as the original.
If specified, the Quantity instances are also copied to the new BGSystem
Parameters
- sys (BGSystem): the original instance used as a template
- copy (Boolean):
TrueifQuantityinstances are also copied
Returns
- newinstance (BGSystem): the new instance
115 def quantity_names(self) -> list[str]: 116 """ 117 Get a list of names for all `Quantity` objects attributed to this BGSystem. 118 119 Returns 120 ------- 121 names : list of str 122 the list of names. 123 """ 124 125 return list(self.quantities.keys())
Get a list of names for all Quantity objects attributed to this BGSystem.
Returns
- names (list of str): the list of names.
128 def initialise(self, quantity : str) -> Callable: 129 """ 130 Instantiate a `Quantity` object from `quantities`. 131 132 The method creates a function `init` which can be called by 133 an arithmetic type / `Callable` to instantiate a `Val` / `Func`. 134 Calling `init` adds and instance of the `Quantity` as a new attribute to the BGSystem, 135 with the attribute name corresponding to the object's `name` attribute. 136 137 Parameters 138 ---------- 139 quantity : str 140 the name of the object which is to be instantiated. 141 142 Returns 143 ------- 144 init : Callable 145 a function used to initialize the `Quantity` object 146 """ 147 148 def init(obj : np.ndarray | Callable): 149 """ 150 Initialize a `Quantity` object with an arithmetic type / Callable. 151 152 This adds an instance of the `Quantity` as a new attribute to the `BGSystem`, with the attribute name 153 corresponding to the `Quantity` object's `name` attribute. 154 155 Parameters 156 ---------- 157 obj : NDArray or Callable 158 the NDArray / Callable with which the `Quantity` is to be instantiated. 159 """ 160 161 q = self.quantities[quantity] 162 setattr( self, quantity, q(obj, self) ) 163 return 164 165 return init
Instantiate a Quantity object from quantities.
The method creates a function init which can be called by
an arithmetic type / Callable to instantiate a Val / Func.
Calling init adds and instance of the Quantity as a new attribute to the BGSystem,
with the attribute name corresponding to the object's name attribute.
Parameters
- quantity (str): the name of the object which is to be instantiated.
Returns
- init (Callable):
a function used to initialize the
Quantityobject
167 def variable_list(self) -> list['Variable']: 168 """ 169 Get a list of all `Variable` instances attributed to this BGSystem. 170 171 Returns 172 ------- 173 vals : list of Variable 174 the list of `Variable` instances. 175 """ 176 177 vals = [] 178 for var in vars(self): 179 obj = getattr(self, var) 180 if isinstance(obj, Variable): 181 vals.append(obj) 182 return vals
184 def variable_names(self) -> list[str]: 185 """ 186 Get a list of names for all `Variable` instances attributed to this BGSystem. 187 188 Returns 189 ------- 190 names : list of str 191 the list of names. 192 """ 193 194 names = [] 195 for val in self.variable_list(): 196 names.append(val.name) 197 return names
Get a list of names for all Variable instances attributed to this BGSystem.
Returns
- names (list of str): the list of names.
199 def constant_list(self) -> list['Constant']: 200 """ 201 Get a list of all `Constant` instances attributed to this BGSystem. 202 203 Returns 204 ------- 205 vals : list of Val 206 the list of `Constant` instances. 207 """ 208 209 vals = [] 210 for var in vars(self): 211 obj = getattr(self, var) 212 if isinstance(obj, Constant): 213 vals.append(obj) 214 return vals
216 def constant_names(self) -> list[str]: 217 """ 218 Get a list of names for all `Constant` instances attributed to this BGSystem. 219 220 Returns 221 ------- 222 names : list of str 223 the list of names. 224 """ 225 226 names = [] 227 for val in self.constant_list(): 228 names.append(val.name) 229 return names
Get a list of names for all Constant instances attributed to this BGSystem.
Returns
- names (list of str): the list of names.
231 def function_list(self) -> list['Func']: 232 """ 233 Get a list of all `Func` instances attributed to this BGSystem. 234 235 Returns 236 ------- 237 funcs : list of Func 238 the list of `Func` instances. 239 """ 240 241 funcs = [] 242 for var in vars(self): 243 obj = getattr(self, var) 244 if isinstance(obj, Func): 245 funcs.append(obj) 246 return funcs
248 def function_names(self) -> list[str]: 249 """ 250 Get a list of names for all `Func` instances attributed to this BGSystem. 251 252 Returns 253 ------- 254 names : list of str 255 the list of names. 256 """ 257 258 names = [] 259 for val in self.function_list(): 260 names.append(val.name) 261 return names
Get a list of names for all Func instances attributed to this BGSystem.
Returns
- names (list of str): the list of names.
263 def remove(self, name : str): 264 """ 265 Remove a `Quantity` object and its instance from the BGSystem. 266 267 Parameters 268 ---------- 269 name : str 270 the name of the object 271 """ 272 273 delattr(self, name) 274 self.quantities.pop(name) 275 return
Remove a Quantity object and its instance from the BGSystem.
Parameters
- name (str): the name of the object
277 def add_variable(self, name : str, qu_omega : int, qu_mu : int): 278 """ 279 Define a new `Variable` object and add it to `quantities`. 280 281 Parameters 282 ---------- 283 name : str 284 the name of the new object. 285 qu_omega : int 286 the 'u_omega' parameter of the new object. 287 qu_mu : int 288 the 'u_mu' parameter of the new object. 289 """ 290 291 self.quantities[name] = define_var(name, qu_omega, qu_mu) 292 return
Define a new Variable object and add it to quantities.
Parameters
- name (str): the name of the new object.
- qu_omega (int): the 'u_omega' parameter of the new object.
- qu_mu (int): the 'u_mu' parameter of the new object.
294 def add_constant(self, name : str, qu_omega : int, qu_mu : int): 295 """ 296 Define a new `Constant` object and add it to `quantities`. 297 298 Parameters 299 ---------- 300 name : str 301 the name of the new object. 302 qu_omega : int 303 the 'u_omega' parameter of the new object. 304 qu_mu : int 305 the 'u_mu' parameter of the new object. 306 """ 307 308 self.quantities[name] = define_const(name, qu_omega, qu_mu) 309 return
Define a new Constant object and add it to quantities.
Parameters
- name (str): the name of the new object.
- qu_omega (int): the 'u_omega' parameter of the new object.
- qu_mu (int): the 'u_mu' parameter of the new object.
311 def add_function(self, name : str, args : list['Val'], qu_omega : int, qu_mu : int): 312 """ 313 Define a new `Func` object and add it to `quantities`. 314 315 Parameters 316 ---------- 317 name : str 318 the name of the new object. 319 args : list of BGVal 320 the 'args' parameter of the new object. 321 qu_omega : int 322 the 'u_omega' parameter of the new object. 323 qu_mu : int 324 the 'u_mu' parameter of the new object. 325 """ 326 327 self.quantities[name] = define_func(name, args, qu_omega, qu_mu) 328 return
Define a new Func object and add it to quantities.
Parameters
- name (str): the name of the new object.
- args (list of BGVal): the 'args' parameter of the new object.
- qu_omega (int): the 'u_omega' parameter of the new object.
- qu_mu (int): the 'u_mu' parameter of the new object.
330 def save_variables(self, path : str): 331 """ 332 Save the data in the current GEF instance in an output file. 333 334 Note, data is always stored in numerical units. 335 The save will not store constants or functions, only variables. 336 337 Parameters 338 ---------- 339 path : str 340 Path to store data in. 341 342 Raises 343 ------ 344 ValueError 345 if the GEF object has no data to store. 346 """ 347 348 storeables = self.variable_names() 349 #Check that all dynamic and derived quantities are initialised in this GEF instance 350 if len(storeables) == 0: 351 raise ValueError("No data to store.") 352 353 #Create a dictionary used to initialise the pandas DataFrame 354 dic = {} 355 356 #remember the original units of the GEF 357 og_units=self.units 358 359 #Data is always stored unitless 360 self.units = False 361 362 for key in storeables: 363 dic[key] = getattr(self, key).value 364 365 #Create pandas data frame and store the dictionary under the user-specified path 366 output_df = pd.DataFrame(dic) 367 output_df.to_csv(path) 368 369 #after storing data, restore original units 370 self.units = og_units 371 return
Save the data in the current GEF instance in an output file.
Note, data is always stored in numerical units. The save will not store constants or functions, only variables.
Parameters
- path (str): Path to store data in.
Raises
- ValueError: if the GEF object has no data to store.
373 def load_variables(self, path : str): 374 """ 375 Load data and store its results in the BGSystem. 376 377 Note, data is always loaded assuming numerical units. 378 Data is only loaded for variables, not for functions or constants. 379 380 Parameters 381 ---------- 382 path : None or str 383 Path to load data from 384 385 Raises 386 ------ 387 FileNotFoundError 388 if no file is found at `path`. 389 AttributeError 390 if the file contains a column labeled by a key which does not match any BGSystem variable. 391 """ 392 #Check if file exists 393 try: 394 #Load from file 395 input_df = pd.read_table(path, sep=",") 396 except FileNotFoundError: 397 raise FileNotFoundError(f"No file found under '{path}'") 398 399 #Dictionary for easy access using keys 400 401 data = dict(zip(input_df.columns[1:],input_df.values[:,1:].T)) 402 403 #Before starting to load, check that the file is compatible with the GEF setup. 404 names = self.quantity_names() 405 for key in data.keys(): 406 if key not in names: 407 raise AttributeError(f"The data table you tried to load contains an unknown quantity: '{key}'") 408 409 #Store current units to switch back to later 410 og_units=self.units 411 412 #GEF data is always stored untiless, thus it is assumed to be untiless when loaded. 413 self.units = False 414 #Load data into background-value attributes 415 for key, values in data.items(): 416 if key in self.variable_names(): 417 getattr(self, key).value = values 418 else: 419 self.initialise(key)(values) 420 421 self.units = og_units 422 return
Load data and store its results in the BGSystem.
Note, data is always loaded assuming numerical units. Data is only loaded for variables, not for functions or constants.
Parameters
- path (None or str): Path to load data from
Raises
- FileNotFoundError: if no file is found at
path. - AttributeError: if the file contains a column labeled by a key which does not match any BGSystem variable.
425class Quantity: 426 name : ClassVar[str]= "" 427 """The objects name""" 428 description : ClassVar[str]= "" 429 """A brief description of the object""" 430 u_omega : ClassVar[int] = 0 431 """Indicates how the object scales with frequency.""" 432 u_mu : ClassVar[int] = 0 433 """Indicates how the object scales with energy.""" 434 435 def __init__(self, sys : BGSystem): 436 """ 437 Create a new Quantity as part of a BGSystem 438 439 The units of the new object matches those of the BGSystem 440 441 Parameters 442 ---------- 443 sys : BGSystem 444 the BGSystem to which the object belongs 445 """ 446 447 self._units = sys.units 448 self._conversion = (sys.omega**self.u_omega*sys.mu**self.u_mu) 449 450 def __repr__(self): 451 r"""A string representing the class, giving its name and scaling with frequency ($\omega$) and energy ($\mu$).""" 452 return f"{self.name}({self.u_omega},{self.u_mu})" 453 454 def __str__(self) -> str: 455 """The class instance as a string including its name and current units.""" 456 457 if not(self._units): 458 return f"{self.name} (numerical)" 459 elif self._units: 460 return f"{self.name} (physical)" 461 462 463 @property 464 def units(self) -> bool: 465 """Indicates the current units of the Quantity. `True`:physical units, `False`:numerical units""" 466 return self._units 467 468 @units.setter 469 def units(self, units : bool): 470 """Convert the object between numerical and physical units.""" 471 self._units = bool(units) 472 return 473 474 @property 475 def conversion(self) -> float: 476 """A conversion factor between numerical and physical units.""" 477 return self._conversion 478 479 @classmethod 480 def get_description(cls) -> str: 481 """Return a string describing the object.""" 482 if cls.description=="": 483 return f"{cls.name}" 484 else: 485 return f"{cls.name} - {cls.description}"
An object representing a cosmological quantity.
A cosmological quantity has a characteristic scaling with respect to a frequency scale (e.g., the Hubble rate at some reference time), and energy scale (e.g., the Planck mass).
Typical such objects are:
- cosmic time $t = \bar{t}/\omega$
- frequency $f = \omega \bar{f}$
- scalar-field vev $\varphi = \mu \bar{\varphi}$
- scalar potential $ V(\varphi) = \omega^2 \mu^2 \bar{V}(\bar{\varphi} \mu) $
- gauge fields $A_\mu = \omega\bar{A}_\mu $ (i.e., scales like a time derivative)
Quantity objects are initialized as part of a BGSystem, which defines $\omega$ and $\mu$.
435 def __init__(self, sys : BGSystem): 436 """ 437 Create a new Quantity as part of a BGSystem 438 439 The units of the new object matches those of the BGSystem 440 441 Parameters 442 ---------- 443 sys : BGSystem 444 the BGSystem to which the object belongs 445 """ 446 447 self._units = sys.units 448 self._conversion = (sys.omega**self.u_omega*sys.mu**self.u_mu)
Create a new Quantity as part of a BGSystem
The units of the new object matches those of the BGSystem
Parameters
- sys (BGSystem): the BGSystem to which the object belongs
463 @property 464 def units(self) -> bool: 465 """Indicates the current units of the Quantity. `True`:physical units, `False`:numerical units""" 466 return self._units
Indicates the current units of the Quantity. True:physical units, False:numerical units
489class Val(Quantity): 490 def __init__(self, value : np.ndarray|float, sys : BGSystem): 491 """ 492 Create a new instance using a BGSystem. 493 494 Parameters 495 ---------- 496 value : NDArray 497 the underlying array of the instance 498 sys : BGSystem 499 the BGSystem to which the instance belongs 500 """ 501 super().__init__(sys) 502 self._value = value*self._conversion**(-sys.units) 503 504 def __str__(self) -> str: 505 """ 506 The class instance as a string including its name, current units, and its value. 507 508 Returns 509 ------- 510 str 511 the string representation. 512 """ 513 514 if not(self._units): 515 return f"{self.name} (numerical): {self.value}" 516 elif self._units: 517 return f"{self.name} (physical): {self.value}" 518 519 @property 520 def value(self) -> float: 521 """The objects value in its respective units.""" 522 return self._value*self._conversion**self._units 523 524 @value.setter 525 def value(self, newval): 526 """Overwrite the `value` attribute (assuming its current units).""" 527 self._value = newval*self._conversion**(-self._units) 528 return 529 530 #Define all mathematical operations as operations acting on self.value 531 def __abs__(self): 532 return abs(self.value) 533 534 def __neg__(self): 535 return -self.value 536 537 def __pos__(self): 538 return +self.value 539 540 def __add__(self, other): 541 #self.__Compatible(self, other, "+") 542 return self.value + other 543 544 __radd__ = __add__ 545 546 def __sub__(self, other): 547 #self.__Compatible(self, other, "-") 548 return self.value - other 549 550 def __rsub__(self, other): 551 return other - self.value 552 553 def __mul__(self, other): 554 return self.value * other 555 556 __rmul__ = __mul__ 557 558 def __floordiv__(self, other): 559 return self.value // other 560 561 def __rfloordiv__(self, other): 562 return other // self.value 563 564 def __truediv__(self, other): 565 return self.value / other 566 567 def __rtruediv__(self, other): 568 return other / self.value 569 570 def __mod__(self, other): 571 return self.value % other 572 573 def __pow__(self, other): 574 #BGVal should never be exponentiated by another BGVal 575 return self.value ** other 576 577 def __eq__(self, other): 578 #self.__Compatible(self, other, "==") 579 return self.value == other 580 581 def __ne__(self, other): 582 #self.__Compatible(self, other, "!=") 583 return self.value != other 584 585 def __lt__(self, other): 586 #self.__Compatible(self, other, "<") 587 return self.value < other 588 589 def __gt__(self, other): 590 #self.__Compatible(self, other, ">") 591 return self.value > other 592 593 def __le__(self, other): 594 #self.__Compatible(self, other, "<=") 595 return self.value <= other 596 597 def __ge__(self, other): 598 #self.__Compatible(self, other, ">=") 599 return self.value >= other
A Quantity subclass used as basis for defining real-valued variables and constants.
In addition to the basic structure defined by Quantity, this class can be used like an arithmetic type.
It defines basic arithmetic operations on its instances as operations on their underlying value attribute.
As a subclass of Quantity it inherits all its attributes and methods, ensuring
that value is changed according to units by using conversion.
490 def __init__(self, value : np.ndarray|float, sys : BGSystem): 491 """ 492 Create a new instance using a BGSystem. 493 494 Parameters 495 ---------- 496 value : NDArray 497 the underlying array of the instance 498 sys : BGSystem 499 the BGSystem to which the instance belongs 500 """ 501 super().__init__(sys) 502 self._value = value*self._conversion**(-sys.units)
Create a new instance using a BGSystem.
Parameters
- value (NDArray): the underlying array of the instance
- sys (BGSystem): the BGSystem to which the instance belongs
519 @property 520 def value(self) -> float: 521 """The objects value in its respective units.""" 522 return self._value*self._conversion**self._units
The objects value in its respective units.
Inherited Members
602class Func(Quantity): 603 args : ClassVar[list[Val]] = [] 604 """Indicates the argument signature for the class.""" 605 dtype : ClassVar[np.floating] = np.float64 606 """The data type returned by `__call__`.""" 607 608 def __init__(self, func : Callable, sys : BGSystem): 609 """ 610 Create a new instance using a `Callable` and a BGSystem 611 612 Parameters 613 ---------- 614 func : NDArray 615 the underlying function `f(*args)` of the instance 616 sys : BGSystem 617 the BGSystem to which the instance belongs 618 619 Raises 620 ------ 621 TypeError 622 if the number of arguments of `func` do not match `args` 623 ValueError 624 if the return of`func` can't be converted to `dtype` 625 """ 626 super().__init__(sys) 627 func = np.vectorize(func, otypes=[self.dtype]) 628 629 try: 630 testargs = [1.0 for arg in self.args] 631 assert func(*testargs).dtype 632 except TypeError: 633 raise TypeError("The number of non-default arguments of 'func' needs to match 'len(self.args)'.") 634 except ValueError: 635 raise ValueError(f"'func' must return a single value which can be converted to '{self.dtype}'") 636 637 self._basefunc = func 638 639 self._arg_conversions = [(sys.omega**arg.u_omega*sys.mu**arg.u_mu) 640 for arg in self.args] 641 642 @property 643 def basefunc(self) -> Callable: 644 """The underlying function which defines the `__call__` method.""" 645 return self._basefunc 646 647 def get_arg_conversions(self) -> list[float]: 648 """ 649 Get a list of conversion factors for each argument of `basefunc`. 650 651 Returns 652 ------- 653 arg_conversions : list of float 654 a list of conversion factors 655 """ 656 657 return self._arg_conversions 658 659 def __call__(self, *args): 660 """ 661 Define the call method of the class as outlined in its documentation. 662 """ 663 def float_handler(x, i): 664 return x*self._arg_conversions[i]**(1-self._units) 665 666 def val_handler(x, i): 667 conv = x.conversion 668 assert self._arg_conversions[i] == conv 669 return x*conv**(1-x.units) 670 671 typedic = {Variable : val_handler, Val : val_handler, Constant: val_handler} 672 673 args = [typedic.get(arg.__class__.__bases__[0], float_handler)(arg, i) for i, arg in enumerate(args)] 674 675 return self._basefunc(*args)/self._conversion**(1-self._units)
A Quantity subclass representing real functions of variables like the inflaton potential.
An instance of this class can be used as a function,
evaluating the underlying method, basefunc depending on the state of units.
In physical units, the call returns the result of basefunc.
In numerical units, the call instead returns basefunc(*args)/conversion.
If called by a Val object, the argument is also converted according to the units of the Val instance
(generically, identical to the ones of the Func instance).
If instead called by a regular arithmetic data type (e.g., float),
it is assumed that the argument is in the same unit system as the Func instance.
A typical object is the scalar potential, $V(\varphi) = \omega^2 \mu^2 \bar{V}(\bar{\varphi} \mu) $
To define a custom Func object, use the class factory define_func.
608 def __init__(self, func : Callable, sys : BGSystem): 609 """ 610 Create a new instance using a `Callable` and a BGSystem 611 612 Parameters 613 ---------- 614 func : NDArray 615 the underlying function `f(*args)` of the instance 616 sys : BGSystem 617 the BGSystem to which the instance belongs 618 619 Raises 620 ------ 621 TypeError 622 if the number of arguments of `func` do not match `args` 623 ValueError 624 if the return of`func` can't be converted to `dtype` 625 """ 626 super().__init__(sys) 627 func = np.vectorize(func, otypes=[self.dtype]) 628 629 try: 630 testargs = [1.0 for arg in self.args] 631 assert func(*testargs).dtype 632 except TypeError: 633 raise TypeError("The number of non-default arguments of 'func' needs to match 'len(self.args)'.") 634 except ValueError: 635 raise ValueError(f"'func' must return a single value which can be converted to '{self.dtype}'") 636 637 self._basefunc = func 638 639 self._arg_conversions = [(sys.omega**arg.u_omega*sys.mu**arg.u_mu) 640 for arg in self.args]
Create a new instance using a Callable and a BGSystem
Parameters
- func (NDArray):
the underlying function
f(*args)of the instance - sys (BGSystem): the BGSystem to which the instance belongs
Raises
642 @property 643 def basefunc(self) -> Callable: 644 """The underlying function which defines the `__call__` method.""" 645 return self._basefunc
The underlying function which defines the __call__ method.
647 def get_arg_conversions(self) -> list[float]: 648 """ 649 Get a list of conversion factors for each argument of `basefunc`. 650 651 Returns 652 ------- 653 arg_conversions : list of float 654 a list of conversion factors 655 """ 656 657 return self._arg_conversions
Get a list of conversion factors for each argument of basefunc.
Returns
- arg_conversions (list of float): a list of conversion factors
Inherited Members
678class Variable(Val): 679 dtype : ClassVar[np.floating] = np.float64 680 """The data type of `value`.""" 681 682 def __init__(self, value : np.ndarray, sys : BGSystem): 683 """ 684 Create a new instance using a numpy array and a BGSystem 685 686 Parameters 687 ---------- 688 value : NDArray 689 the underlying array of the instance 690 sys : BGSystem 691 the BGSystem to which the instance belongs 692 """ 693 super().__init__( np.asarray(value, dtype=self.dtype), sys) 694 695 #The following methods ensure that a `Val` instance can be used as an array concerning mathematical operations and indexing. 696 697 def __getitem__(self, idx): 698 return self.value[idx] 699 700 def __len__(self): 701 return len(self.value) 702 703 @property 704 def value(self) -> np.ndarray: 705 """The objects value in its respective units.""" 706 return self._value*self._conversion**(self._units) 707 708 @value.setter 709 def value(self, newval): 710 """Overwrite the `value` attribute ensuring it is an array""" 711 self._value = np.asarray(newval*self._conversion**(-self._units), dtype=self.dtype) 712 return
A Val subclass representing real-valued variables evolving with cosmic time.
Instances of this class can be used like a Val with value as a 1-D Numpy-Array.
Indexed returns the associated index of value.
682 def __init__(self, value : np.ndarray, sys : BGSystem): 683 """ 684 Create a new instance using a numpy array and a BGSystem 685 686 Parameters 687 ---------- 688 value : NDArray 689 the underlying array of the instance 690 sys : BGSystem 691 the BGSystem to which the instance belongs 692 """ 693 super().__init__( np.asarray(value, dtype=self.dtype), sys)
Create a new instance using a numpy array and a BGSystem
Parameters
- value (NDArray): the underlying array of the instance
- sys (BGSystem): the BGSystem to which the instance belongs
703 @property 704 def value(self) -> np.ndarray: 705 """The objects value in its respective units.""" 706 return self._value*self._conversion**(self._units)
The objects value in its respective units.
Inherited Members
714class Constant(Val): 715 def __init__(self, value, sys : BGSystem): 716 """ 717 Create a new instance using a float and a BGSystem 718 719 Parameters 720 ---------- 721 value : NDArray 722 the underlying array of the instance 723 sys : BGSystem 724 the BGSystem to which the instance belongs 725 726 Raises 727 ------ 728 TypeError 729 if value cannot be converted to a float 730 """ 731 super().__init__( float(value), sys)
A Val subclass representing a constant of cosmic time.
Instances of this class can be used like a float for mathematical operations as defined by Val.
715 def __init__(self, value, sys : BGSystem): 716 """ 717 Create a new instance using a float and a BGSystem 718 719 Parameters 720 ---------- 721 value : NDArray 722 the underlying array of the instance 723 sys : BGSystem 724 the BGSystem to which the instance belongs 725 726 Raises 727 ------ 728 TypeError 729 if value cannot be converted to a float 730 """ 731 super().__init__( float(value), sys)
Create a new instance using a float and a BGSystem
Parameters
- value (NDArray): the underlying array of the instance
- sys (BGSystem): the BGSystem to which the instance belongs
Raises
- TypeError: if value cannot be converted to a float
Inherited Members
733class GaugeField: 734 name : ClassVar[str] = "" 735 """The name of the class.""" 736 zeros : ClassVar[list[Variable]]= [] 737 r"""A list of the associated 0$^{\rm th}$ order quantities.""" 738 cutoff : Variable = None 739 """The associated UV cutoff scale.""" 740 741 @classmethod 742 def get_description(cls) -> str: 743 """Return a string describing the object.""" 744 return f"{cls.name} - associated with: {[a.name for a in cls.zeros]}, UV cutoff: {cls.cutoff.name}"
$\newcommand{\bm}[1]{\boldsymbol{#1}}$ A low level class defining some basic properties of gauge-field bilinear towers.
A gauge-field bilinear tower is defined as a collection of the following three objects,
$$ \mathcal{F}_\mathcal{E}^{(n)} = \frac{a^4}{k_{{\rm UV}}^{n+4}}\langle \bm{E} \cdot \operatorname{rot}^n \bm{E}\rangle = \int\limits_{0}^{k_{{\rm UV}}(t)}\frac{{\rm d} k}{k} \frac{a^2 k^{n+3}}{2 \pi^2 k_{{\rm UV}}^{n+4}} \sum_{\lambda}\lambda^n |\dot{A}_\lambda(t,k)|^2\, ,$$ $$ \mathcal{F}_\mathcal{G}^{(n)} = -\frac{a^4}{2 k_{{\rm UV}}^{n+4}}\langle \bm{E} \cdot \operatorname{rot}^n \bm{B} + \bm{B} \cdot \operatorname{rot}^n \bm{E}\rangle = \int\limits_{0}^{k_{{\rm UV}}(t)} \frac{{\rm d} k}{k} \frac{a k^{n+4}}{2 \pi^2 k_{{\rm UV}}^{n+4}}\sum_{\lambda}\lambda^{n+1} \operatorname{Re}[\dot{A}_\lambda(t,k)A_\lambda^*(t,k)] \, ,$$ $$ \mathcal{F}_\mathcal{B}^{(n)} = \frac{a^4}{k_{{\rm UV}}^{n+4}}\langle \bm{E} \cdot \operatorname{rot}^n \bm{E}\rangle = \int\limits_{0}^{k_{{\rm UV}}(t)}\frac{{\rm d} k}{k} \frac{k^{n+5}}{2 \pi^{2}k_{{\rm UV}}^{n+4}} \sum_{\lambda}\lambda^n |A_\lambda(t,k)|^2 \, ,$$
here $k_{\rm UV}$ is a UV cutoff scale, $\bm{E}$ and $\bm{B}$ are electric and magnetic field operators, and $A_\lambda(t,k)$ is a gauge-field mode function. The integer $n$ varies between $0$ and a maximum value, $n_{\rm tr}$.
The GaugeField class collects important information about the collection $\mathcal{F}_\mathcal{X}^{(n)}$.
The GEFF code needs to know, which Variable sets the UV cutoff scale, and
which Variables correspond to the zero-order quantities, $\langle \bm{E}^2\rangle$, $\langle \bm{B}^2\rangle$, and $-\langle \bm{E} \cdot \bm{B}\rangle$.
Note that a GaugeField is never part of a BGSystem, as the number of variables depends on $n_{\rm tr}$, which is not fixed a priori.
In fact, terms with $n>1$ are often only auxiliary and not used by the GEFF after the differential equations have been solved.
However, the quantities $\mathcal{F}_\mathcal{X}^{(n)}$ are defined to be unitless, so they do not need to be converted between numerical and physical units.
A custom GaugeField can be defined using BGGauge.
746def define_var(qname : str, qu_omega : int, qu_mu : int, qdescription:str="", qdtype : np.dtype=np.float64): 747 """ 748 Creates a subclass of `Variable` with custom name, and scaling. 749 750 Parameters 751 ---------- 752 qname : str 753 the `name` attribute of the subclass 754 qu_omega : int 755 the `u_omega` attribute of the subclass 756 qu_mu : int 757 the `u_mu` attribute of the subclass 758 qdescription : str 759 a brief description of the subclass 760 qdtype : Numpy Data Type 761 the `dtype` attribute of the subclass 762 763 764 Returns 765 ------- 766 CustomVar : class 767 the custom subclass 768 769 Raises 770 ------ 771 TypeError 772 if the data type is not a subtype of `numpy.floating` 773 """ 774 775 if not( np.issubdtype(qdtype, np.floating) ): 776 raise TypeError("BGVal's data-type must be a subtype of 'numpy.floating'.") 777 778 class CustomVar(Variable): 779 __doc__ = docs_bgtypes.DOCS["define_var.CustomVar"] 780 name=qname 781 u_omega = qu_omega 782 u_mu = qu_mu 783 dtype = qdtype 784 description = qdescription 785 def __init__(self, value, sys): 786 super().__init__(value, sys) 787 CustomVar.__qualname__ = f"Val_{qname}" 788 CustomVar.__module__ = __name__ 789 790 return CustomVar
Creates a subclass of Variable with custom name, and scaling.
Parameters
- qname (str):
the
nameattribute of the subclass - qu_omega (int):
the
u_omegaattribute of the subclass - qu_mu (int):
the
u_muattribute of the subclass - qdescription (str): a brief description of the subclass
- qdtype (Numpy Data Type):
the
dtypeattribute of the subclass
Returns
- CustomVar (class): the custom subclass
Raises
- TypeError: if the data type is not a subtype of
numpy.floating
792def define_const(qname : str, qu_omega : int, qu_mu : int, qdescription:str=""): 793 """ 794 Creates a subclass of `Constant` with custom name, and scaling. 795 796 Parameters 797 ---------- 798 qname : str 799 the `name` attribute of the subclass 800 qu_omega : int 801 the `u_omega` attribute of the subclass 802 qu_mu : int 803 the `u_mu` attribute of the subclass 804 qdescription : str 805 a brief description of the subclass 806 807 Returns 808 ------- 809 CustomConst : class 810 the custom subclass 811 """ 812 813 class CustomConst(Constant): 814 __doc__ = docs_bgtypes.DOCS["define_const.CustomConst"] 815 name=qname 816 u_omega = qu_omega 817 u_mu = qu_mu 818 description = qdescription 819 def __init__(self, value, sys): 820 super().__init__(value, sys) 821 CustomConst.__qualname__ = f"Const_{qname}" 822 CustomConst.__module__ = __name__ 823 824 return CustomConst
Creates a subclass of Constant with custom name, and scaling.
Parameters
- qname (str):
the
nameattribute of the subclass - qu_omega (int):
the
u_omegaattribute of the subclass - qu_mu (int):
the
u_muattribute of the subclass - qdescription (str): a brief description of the subclass
Returns
- CustomConst (class): the custom subclass
828def define_func(qname : str, func_args : list[Val], qu_omega : int, qu_mu : int, qdescription:str="", qdtype : np.dtype=np.float64): 829 """ 830 Creates a subclass of `Func` with custom name, scaling, and argument signature. 831 832 Parameters 833 ---------- 834 qname : str 835 the `name` attribute of the subclass 836 qu_omega : int 837 the `u_omega` attribute of the subclass 838 qu_mu : int 839 the `u_mu` attribute of the subclass 840 qdtype : Numpy Data Type 841 the `dtype` attribute of the subclass 842 qdescription : str 843 a brief description of the subclass 844 845 Returns 846 ------- 847 CustomFunc : class 848 the custom subclass 849 850 Raises 851 ------ 852 TypeError 853 if the data type is not a subtype of `numpy.floating` 854 """ 855 856 if not( np.issubdtype(qdtype, np.floating) ): 857 raise TypeError("define_func's data-type must be a subtype of 'np.floating'.") 858 859 class CustomFunc(Func): 860 __doc__ = docs_bgtypes.DOCS["define_func.CustomFunc"] 861 name=qname 862 u_omega = qu_omega 863 u_mu = qu_mu 864 args = func_args 865 dtype = qdtype 866 description = qdescription 867 def __init__(self, func, sys): 868 super().__init__(func, sys) 869 870 CustomFunc.__qualname__ = f"Func_{qname}" 871 CustomFunc.__module__ = __name__ 872 873 return CustomFunc
Creates a subclass of Func with custom name, scaling, and argument signature.
Parameters
- qname (str):
the
nameattribute of the subclass - qu_omega (int):
the
u_omegaattribute of the subclass - qu_mu (int):
the
u_muattribute of the subclass - qdtype (Numpy Data Type):
the
dtypeattribute of the subclass - qdescription (str): a brief description of the subclass
Returns
- CustomFunc (class): the custom subclass
Raises
- TypeError: if the data type is not a subtype of
numpy.floating
875def define_gauge(qname : str, qzeros : list[Variable], qcutoff : Variable): 876 """ 877 A class factory creating custom `GaugeField` classes with new name, zero variables, and cutoff scale. 878 879 Parameters 880 ---------- 881 qname : str 882 the `name` attribute of the subclass 883 qzeros : list of Variable 884 the `zeros` attribute of the new subclass 885 qcutoff : Variable 886 the `cutoff` attribute of the new subclass 887 888 Returns 889 ------- 890 CustomGaugeField : class 891 the custom subclass 892 """ 893 class CustomGaugeField(GaugeField): 894 name = qname 895 zeros = qzeros 896 cutoff = qcutoff 897 898 CustomGaugeField.__qualname__ = f"GaugeField_{qname}" 899 CustomGaugeField.__module__ = __name__ 900 return CustomGaugeField
A class factory creating custom GaugeField classes with new name, zero variables, and cutoff scale.
Parameters
- qname (str):
the
nameattribute of the subclass - qzeros (list of Variable):
the
zerosattribute of the new subclass - qcutoff (Variable):
the
cutoffattribute of the new subclass
Returns
- CustomGaugeField (class): the custom subclass