buckinghampi module
1074 |buckinghampi.py: a symbolic module that generates the pi terms based on some variables by applying the pi-theorem.
1075 | 1076 | 1077 |"""buckinghampi.py: a symbolic module that generates the pi terms based on some variables by applying the pi-theorem.""" 1079 | 1080 | __author__ = "Mokbel Karam" 1081 | __copyright__ = "Copyright (c) 2021, Mokbel Karam" 1082 | 1083 | __credits__ = ["University of Utah Department of Chemical Engineering"] 1084 | __license__ = "MIT" 1085 | __version__ = "1.0.3" 1086 | __maintainer__ = "Mokbel Karam" 1087 | __email__ = "karammokbel@gmail.com" 1088 | __status__ = "Production" 1089 | 1090 | import sympy as sp 1091 | from sympy.parsing.sympy_parser import parse_expr 1092 | from sympy.core.mul import Mul, Pow 1093 | from sympy.core.expr import Expr 1094 | import numpy as np 1095 | from itertools import combinations,permutations 1096 | from tabulate import tabulate 1097 | 1098 | try: 1099 | from IPython.display import display, clear_output, Math, Markdown 1100 | except: 1101 | pass 1102 | 1103 | class BuckinghamPi: 1104 | def __init__(self): 1105 | ''' 1106 | Construct an instance of the BuckinghamPi theorem 1107 | ''' 1108 | self.__var_from_idx={} 1109 | self.__idx_from_var = {} 1110 | self.__variables={} 1111 | self.__sym_variables={} 1112 | self.__flagged_var = {'var_name':None, 'var_index':None,'selected':False} 1113 | 1114 | self.__null_spaces = [] 1115 | 1116 | self.__fundamental_vars_used = [] # list of fundamental variables being used 1117 | 1118 | @property 1119 | def fundamental_variables(self): 1120 | ''' 1121 | :return: a list of the fundamental variables being used 1122 | ''' 1123 | return self.__fundamental_vars_used 1124 | 1125 | @property 1126 | def variables(self): 1127 | ''' 1128 | :return: a dict of the variables added by the user. 1129 | ''' 1130 | return self.__variables 1131 | 1132 | 1133 | def __parse_expression(self,string:str): 1134 | if '^' in string: 1135 | # convert the xor operator to power operator 1136 | string = string.replace('^','**') 1137 | 1138 | expr = parse_expr(string.lower()) 1139 | 1140 | if not (isinstance(expr,Mul) or isinstance(expr,Pow) or isinstance(expr,sp.Symbol)): 1141 | raise Exception('expression of type {} is not of the accepted types ({}, {}, {})'.format(type(expr), Mul, Pow, sp.Symbol)) 1142 | if expr.as_coeff_Mul()[0] != 1: 1143 | raise Exception('cannot have coefficients, {}, that multiply the expression {}'.format(expr.as_coeff_Mul()[0],expr.as_coeff_Mul()[1])) 1144 | 1145 | #extract the physical dimensions from the units expressions 1146 | used_symbols = list(expr.free_symbols) 1147 | for sym in used_symbols: 1148 | if not sym in self.__fundamental_vars_used: 1149 | self.__fundamental_vars_used.append(sym) 1150 | 1151 | return expr 1152 | 1153 | def __extract_exponents(self,expr:Expr): 1154 | num_physical_dimensions = len(self.__fundamental_vars_used) 1155 | vect = np.zeros(num_physical_dimensions) 1156 | args = list(expr.args) if list(expr.args) else [expr] 1157 | # print(args) 1158 | if isinstance(expr, Pow): 1159 | vect[self.__fundamental_vars_used.index(args[0])] = int(args[1]) 1160 | else: 1161 | for e in args: 1162 | if isinstance(expr, sp.Symbol): 1163 | vect[self.__fundamental_vars_used.index(e)]= int(1) 1164 | # print('({}, {})'.format(e, 1)) 1165 | else: 1166 | var, exponent= e.as_base_exp() 1167 | vect[self.__fundamental_vars_used.index(var)] = int(exponent) 1168 | # print('({}, {})'.format(var, exponent)) 1169 | 1170 | return vect 1171 | 1172 | def add_variable(self, name: str, units: str, non_repeating=False): 1173 | ''' 1174 | Add variables to use for the pi-theorem 1175 | :param name: (string) name of the variable to be added 1176 | :param units: (string) expression of the independent physical variable expressed in terms of the k independent fundamental units. 1177 | :param non_repeating: (boolean) select a variable to belong to the non-repeating variables matrix. This will ensure that the selected variable 1178 | only shows up in one dimensionless group. 1179 | ''' 1180 | expr = self.__parse_expression(units) 1181 | self.__variables.update({name:expr}) 1182 | var_idx = len(list(self.__variables.keys()))-1 1183 | self.__var_from_idx[var_idx]= name 1184 | self.__idx_from_var[name] = var_idx 1185 | if non_repeating and (self.__flagged_var['selected'] == False): 1186 | self.__flagged_var['var_name'] = name 1187 | self.__flagged_var['var_index'] = var_idx 1188 | self.__flagged_var['selected'] = True 1189 | elif non_repeating and (self.__flagged_var['selected'] == True): 1190 | raise Exception("you cannot select more than one variable at a time to be a non_repeating.") 1191 | 1192 | def __create_M(self): 1193 | self.num_variable = len(list(self.__variables.keys())) 1194 | num_physical_dimensions = len(self.__fundamental_vars_used) 1195 | if self.num_variable <= num_physical_dimensions: 1196 | raise Exception('The number of variables has to be greater than the number of physical dimensions.') 1197 | 1198 | self.M = np.zeros(shape=(self.num_variable, num_physical_dimensions)) 1199 | # fill M 1200 | for var_name in self.__variables.keys(): 1201 | expr = self.__variables[var_name] 1202 | vect = self.__extract_exponents(expr) 1203 | row = self.__idx_from_var[var_name] 1204 | self.M[row, :] = vect 1205 | 1206 | self.M = self.M.transpose() 1207 | 1208 | def __create_symbolic_variables(self): 1209 | for var_name in self.__variables.keys(): 1210 | self.__sym_variables[var_name] = sp.symbols(var_name) 1211 | 1212 | def __solve_null_spaces(self): 1213 | if self.__flagged_var['selected']==True: 1214 | self.__solve_null_spaces_for_flagged_variables() 1215 | 1216 | else: 1217 | for idx in self.__var_from_idx.keys(): 1218 | self.__flagged_var['var_name'] = self.__var_from_idx[idx] 1219 | self.__flagged_var['var_index'] = idx 1220 | self.__flagged_var['selected'] = True 1221 | 1222 | self.__solve_null_spaces_for_flagged_variables() 1223 | 1224 | def __solve_null_spaces_for_flagged_variables(self): 1225 | 1226 | assert self.__flagged_var['selected']==True, " you need to select a variable to be explicit" 1227 | 1228 | n = self.num_variable 1229 | m = len(self.__fundamental_vars_used) 1230 | 1231 | original_indicies = list(range(0, n)) 1232 | all_idx = original_indicies.copy() 1233 | if self.__flagged_var['selected']: 1234 | del all_idx[self.__flagged_var['var_index']] 1235 | 1236 | # print(all_idx) 1237 | all_combs = list(combinations(all_idx,m)) 1238 | # print(all_combs) 1239 | 1240 | num_det_0 = 0 1241 | for comb in all_combs: 1242 | temp_comb = list(comb).copy() 1243 | extra_vars = [i for i in original_indicies if i not in temp_comb ] 1244 | b_ns = [] 1245 | for extra_var in extra_vars: 1246 | new_order = {} 1247 | temp_comb.append(extra_var) 1248 | A = self.M[:,temp_comb].copy() 1249 | for num,var_idx in enumerate(temp_comb): 1250 | new_order[num] = self.__var_from_idx[var_idx] 1251 | B = sp.Matrix(A) 1252 | test_mat = B[:,:m] 1253 | if sp.det(test_mat) !=0: 1254 | ns = B.nullspace()[0] 1255 | b_ns.append({'order': new_order, 'power': ns.tolist()}) 1256 | 1257 | else: 1258 | num_det_0+=1 1259 | temp_comb = list(comb).copy() 1260 | if b_ns: # if b_ns is not empty add it to the nullspaces list 1261 | self.__null_spaces.append(b_ns) 1262 | # print("num of det 0 : ",num_det_0) 1263 | 1264 | def __construct_symbolic_pi_terms(self): 1265 | self.__allpiterms = [] 1266 | for space in self.__null_spaces: 1267 | spacepiterms = [] 1268 | for term in space: 1269 | expr = 1 1270 | idx = 0 1271 | for order,power in zip(term['order'].keys(),term['power']): 1272 | expr *= self.__sym_variables[term['order'][order]] ** sp.nsimplify(sp.Rational(power[0])) 1273 | idx += 1 1274 | spacepiterms.append(expr) 1275 | # check for already existing pi terms in previous null-spaces 1276 | already_exists = False 1277 | for previouspiterms in self.__allpiterms: 1278 | if all(x in previouspiterms for x in spacepiterms): 1279 | already_exists = True 1280 | break 1281 | if not already_exists: 1282 | self.__allpiterms.append(spacepiterms) 1283 | 1284 | def __rm_duplicated_powers(self): 1285 | # this algorithm rely on the fact that the nullspace function 1286 | # in sympy set one free variable to 1 and the all other to zero 1287 | # then solve the system by back substitution. 1288 | duplicate = [] 1289 | dummy_other_terms = self.__allpiterms.copy() 1290 | for num_set, pi_set in enumerate(self.__allpiterms): 1291 | dummy_other_terms.remove(pi_set) 1292 | for num_other, other in enumerate(dummy_other_terms): 1293 | permutations_sets = permutations(pi_set) 1294 | for p_set in permutations_sets: 1295 | # create a permutation vector from the permutation set 1296 | p_V = sp.Matrix(list(p_set)) 1297 | # create a vector from the other set of dimensionless groups that we are comparing to. 1298 | o_V = sp.Matrix(other) 1299 | # create an element wise inverse of the vector of dimensionless groups 1300 | o_V_inv = o_V.applyfunc(lambda x:x**(-1)) 1301 | 1302 | result = sp.matrix_multiply_elementwise(p_V, o_V) 1303 | # obtain the index of numerical value in the result vector. 1304 | # numerical values indicates that one dimensionless group is the inverse of the other group 1305 | # in this algorithm the numerical value will be equal to 1 (this is a result of the nullspace function in sympy) 1306 | idx_num_result = [x for x in range(len(p_set)) if isinstance(result[x,0],sp.Number)] 1307 | # also repeat the multiplication with the inverse vector 1308 | result_inv = sp.matrix_multiply_elementwise(p_V, o_V_inv) 1309 | # check for the index of the numerical values in the result vector 1310 | idx_num_result_inv = [x for x in range(len(p_set)) if isinstance(result_inv[x,0],sp.Number)] 1311 | # concatinate the indices into one list 1312 | all_indices = idx_num_result + idx_num_result_inv 1313 | # compare if the two vector are duplicates 1314 | if set(all_indices) == set(list(range(len(p_set)))): 1315 | duplicate.append(pi_set) 1316 | 1317 | # remove duplicates from the main dict of all pi terms 1318 | for dup in duplicate: 1319 | self.__allpiterms.remove(dup) 1320 | return duplicate 1321 | 1322 | def generate_pi_terms(self): 1323 | ''' 1324 | Generates all the possible pi terms 1325 | ''' 1326 | self.__create_M() 1327 | 1328 | self.__create_symbolic_variables() 1329 | 1330 | self.__solve_null_spaces() 1331 | 1332 | self.__construct_symbolic_pi_terms() 1333 | 1334 | self.__rm_duplicated_powers() 1335 | 1336 | @property 1337 | def pi_terms(self): 1338 | ''' 1339 | :return: a list with all the symbolic dimensionless terms for all permutation of the dimensional Matrix M 1340 | ''' 1341 | return self.__allpiterms 1342 | 1343 | 1344 | def __Jupyter_print(self): 1345 | ''' print the rendered Latex format in Jupyter cell''' 1346 | for set_num, space in enumerate(self.__allpiterms): 1347 | latex_str= '\\text{Set }' 1348 | latex_str+='{}: \\quad'.format(set_num+1) 1349 | for num, term in enumerate(space): 1350 | latex_str += '\\pi_{} = '.format(num+1)+sp.latex(term) 1351 | latex_str += '\\quad' 1352 | display(Math(latex_str)) 1353 | display(Markdown('---')) 1354 | 1355 | def __tabulate_print(self,latex_string=False): 1356 | ''' print the dimensionless sets in a tabulated format''' 1357 | 1358 | latex_form = [] 1359 | for pi_set in self.__allpiterms: 1360 | latex_set = [] 1361 | for pi in pi_set: 1362 | if latex_string: 1363 | if latex_string: 1364 | latex_set.append(sp.latex(pi)) 1365 | else: 1366 | latex_set.append(pi) 1367 | else: 1368 | latex_set.append(pi) 1369 | latex_form.append(latex_set) 1370 | 1371 | num_of_pi_terms = len(latex_form[0]) 1372 | 1373 | headers = ['sets'] 1374 | for num in range(num_of_pi_terms): 1375 | headers.append('Pi {}'.format(num + 1)) 1376 | 1377 | for num, set in enumerate(latex_form): 1378 | set.insert(0, num + 1) 1379 | 1380 | print(tabulate(latex_form, headers=headers)) 1381 | 1382 | def print_all(self, latex_string=False): 1383 | ''' 1384 | print all the sets of dimensionless groups in latex or symbolic form. 1385 | :latex_string: optional boolean. If set to True the function will print the latex string of the 1386 | dimensionless groups. if set to False the function will print the symbolic form of the 1387 | dimensionless groups. 1388 | ''' 1389 | try: 1390 | ''' Try to render the latex in Jupyter cell''' 1391 | self.__Jupyter_print() 1392 | except: 1393 | ''' print the dimensionless sets in a tabulated format when in terminal session''' 1394 | self.__tabulate_print(latex_string) 1395 |
Classes
1405 | 1406 |class BuckinghamPi
1408 | 1409 | 1410 |class BuckinghamPi: 1414 | def __init__(self): 1415 | ''' 1416 | Construct an instance of the BuckinghamPi theorem 1417 | ''' 1418 | self.__var_from_idx={} 1419 | self.__idx_from_var = {} 1420 | self.__variables={} 1421 | self.__sym_variables={} 1422 | self.__flagged_var = {'var_name':None, 'var_index':None,'selected':False} 1423 | 1424 | self.__null_spaces = [] 1425 | 1426 | self.__fundamental_vars_used = [] # list of fundamental variables being used 1427 | 1428 | @property 1429 | def fundamental_variables(self): 1430 | ''' 1431 | :return: a list of the fundamental variables being used 1432 | ''' 1433 | return self.__fundamental_vars_used 1434 | 1435 | @property 1436 | def variables(self): 1437 | ''' 1438 | :return: a dict of the variables added by the user. 1439 | ''' 1440 | return self.__variables 1441 | 1442 | 1443 | def __parse_expression(self,string:str): 1444 | if '^' in string: 1445 | # convert the xor operator to power operator 1446 | string = string.replace('^','**') 1447 | 1448 | expr = parse_expr(string.lower()) 1449 | 1450 | if not (isinstance(expr,Mul) or isinstance(expr,Pow) or isinstance(expr,sp.Symbol)): 1451 | raise Exception('expression of type {} is not of the accepted types ({}, {}, {})'.format(type(expr), Mul, Pow, sp.Symbol)) 1452 | if expr.as_coeff_Mul()[0] != 1: 1453 | raise Exception('cannot have coefficients, {}, that multiply the expression {}'.format(expr.as_coeff_Mul()[0],expr.as_coeff_Mul()[1])) 1454 | 1455 | #extract the physical dimensions from the units expressions 1456 | used_symbols = list(expr.free_symbols) 1457 | for sym in used_symbols: 1458 | if not sym in self.__fundamental_vars_used: 1459 | self.__fundamental_vars_used.append(sym) 1460 | 1461 | return expr 1462 | 1463 | def __extract_exponents(self,expr:Expr): 1464 | num_physical_dimensions = len(self.__fundamental_vars_used) 1465 | vect = np.zeros(num_physical_dimensions) 1466 | args = list(expr.args) if list(expr.args) else [expr] 1467 | # print(args) 1468 | if isinstance(expr, Pow): 1469 | vect[self.__fundamental_vars_used.index(args[0])] = int(args[1]) 1470 | else: 1471 | for e in args: 1472 | if isinstance(expr, sp.Symbol): 1473 | vect[self.__fundamental_vars_used.index(e)]= int(1) 1474 | # print('({}, {})'.format(e, 1)) 1475 | else: 1476 | var, exponent= e.as_base_exp() 1477 | vect[self.__fundamental_vars_used.index(var)] = int(exponent) 1478 | # print('({}, {})'.format(var, exponent)) 1479 | 1480 | return vect 1481 | 1482 | def add_variable(self, name: str, units: str, non_repeating=False): 1483 | ''' 1484 | Add variables to use for the pi-theorem 1485 | :param name: (string) name of the variable to be added 1486 | :param units: (string) expression of the independent physical variable expressed in terms of the k independent fundamental units. 1487 | :param non_repeating: (boolean) select a variable to belong to the non-repeating variables matrix. This will ensure that the selected variable 1488 | only shows up in one dimensionless group. 1489 | ''' 1490 | expr = self.__parse_expression(units) 1491 | self.__variables.update({name:expr}) 1492 | var_idx = len(list(self.__variables.keys()))-1 1493 | self.__var_from_idx[var_idx]= name 1494 | self.__idx_from_var[name] = var_idx 1495 | if non_repeating and (self.__flagged_var['selected'] == False): 1496 | self.__flagged_var['var_name'] = name 1497 | self.__flagged_var['var_index'] = var_idx 1498 | self.__flagged_var['selected'] = True 1499 | elif non_repeating and (self.__flagged_var['selected'] == True): 1500 | raise Exception("you cannot select more than one variable at a time to be a non_repeating.") 1501 | 1502 | def __create_M(self): 1503 | self.num_variable = len(list(self.__variables.keys())) 1504 | num_physical_dimensions = len(self.__fundamental_vars_used) 1505 | if self.num_variable <= num_physical_dimensions: 1506 | raise Exception('The number of variables has to be greater than the number of physical dimensions.') 1507 | 1508 | self.M = np.zeros(shape=(self.num_variable, num_physical_dimensions)) 1509 | # fill M 1510 | for var_name in self.__variables.keys(): 1511 | expr = self.__variables[var_name] 1512 | vect = self.__extract_exponents(expr) 1513 | row = self.__idx_from_var[var_name] 1514 | self.M[row, :] = vect 1515 | 1516 | self.M = self.M.transpose() 1517 | 1518 | def __create_symbolic_variables(self): 1519 | for var_name in self.__variables.keys(): 1520 | self.__sym_variables[var_name] = sp.symbols(var_name) 1521 | 1522 | def __solve_null_spaces(self): 1523 | if self.__flagged_var['selected']==True: 1524 | self.__solve_null_spaces_for_flagged_variables() 1525 | 1526 | else: 1527 | for idx in self.__var_from_idx.keys(): 1528 | self.__flagged_var['var_name'] = self.__var_from_idx[idx] 1529 | self.__flagged_var['var_index'] = idx 1530 | self.__flagged_var['selected'] = True 1531 | 1532 | self.__solve_null_spaces_for_flagged_variables() 1533 | 1534 | def __solve_null_spaces_for_flagged_variables(self): 1535 | 1536 | assert self.__flagged_var['selected']==True, " you need to select a variable to be explicit" 1537 | 1538 | n = self.num_variable 1539 | m = len(self.__fundamental_vars_used) 1540 | 1541 | original_indicies = list(range(0, n)) 1542 | all_idx = original_indicies.copy() 1543 | if self.__flagged_var['selected']: 1544 | del all_idx[self.__flagged_var['var_index']] 1545 | 1546 | # print(all_idx) 1547 | all_combs = list(combinations(all_idx,m)) 1548 | # print(all_combs) 1549 | 1550 | num_det_0 = 0 1551 | for comb in all_combs: 1552 | temp_comb = list(comb).copy() 1553 | extra_vars = [i for i in original_indicies if i not in temp_comb ] 1554 | b_ns = [] 1555 | for extra_var in extra_vars: 1556 | new_order = {} 1557 | temp_comb.append(extra_var) 1558 | A = self.M[:,temp_comb].copy() 1559 | for num,var_idx in enumerate(temp_comb): 1560 | new_order[num] = self.__var_from_idx[var_idx] 1561 | B = sp.Matrix(A) 1562 | test_mat = B[:,:m] 1563 | if sp.det(test_mat) !=0: 1564 | ns = B.nullspace()[0] 1565 | b_ns.append({'order': new_order, 'power': ns.tolist()}) 1566 | 1567 | else: 1568 | num_det_0+=1 1569 | temp_comb = list(comb).copy() 1570 | if b_ns: # if b_ns is not empty add it to the nullspaces list 1571 | self.__null_spaces.append(b_ns) 1572 | # print("num of det 0 : ",num_det_0) 1573 | 1574 | def __construct_symbolic_pi_terms(self): 1575 | self.__allpiterms = [] 1576 | for space in self.__null_spaces: 1577 | spacepiterms = [] 1578 | for term in space: 1579 | expr = 1 1580 | idx = 0 1581 | for order,power in zip(term['order'].keys(),term['power']): 1582 | expr *= self.__sym_variables[term['order'][order]] ** sp.nsimplify(sp.Rational(power[0])) 1583 | idx += 1 1584 | spacepiterms.append(expr) 1585 | # check for already existing pi terms in previous null-spaces 1586 | already_exists = False 1587 | for previouspiterms in self.__allpiterms: 1588 | if all(x in previouspiterms for x in spacepiterms): 1589 | already_exists = True 1590 | break 1591 | if not already_exists: 1592 | self.__allpiterms.append(spacepiterms) 1593 | 1594 | def __rm_duplicated_powers(self): 1595 | # this algorithm rely on the fact that the nullspace function 1596 | # in sympy set one free variable to 1 and the all other to zero 1597 | # then solve the system by back substitution. 1598 | duplicate = [] 1599 | dummy_other_terms = self.__allpiterms.copy() 1600 | for num_set, pi_set in enumerate(self.__allpiterms): 1601 | dummy_other_terms.remove(pi_set) 1602 | for num_other, other in enumerate(dummy_other_terms): 1603 | permutations_sets = permutations(pi_set) 1604 | for p_set in permutations_sets: 1605 | # create a permutation vector from the permutation set 1606 | p_V = sp.Matrix(list(p_set)) 1607 | # create a vector from the other set of dimensionless groups that we are comparing to. 1608 | o_V = sp.Matrix(other) 1609 | # create an element wise inverse of the vector of dimensionless groups 1610 | o_V_inv = o_V.applyfunc(lambda x:x**(-1)) 1611 | 1612 | result = sp.matrix_multiply_elementwise(p_V, o_V) 1613 | # obtain the index of numerical value in the result vector. 1614 | # numerical values indicates that one dimensionless group is the inverse of the other group 1615 | # in this algorithm the numerical value will be equal to 1 (this is a result of the nullspace function in sympy) 1616 | idx_num_result = [x for x in range(len(p_set)) if isinstance(result[x,0],sp.Number)] 1617 | # also repeat the multiplication with the inverse vector 1618 | result_inv = sp.matrix_multiply_elementwise(p_V, o_V_inv) 1619 | # check for the index of the numerical values in the result vector 1620 | idx_num_result_inv = [x for x in range(len(p_set)) if isinstance(result_inv[x,0],sp.Number)] 1621 | # concatinate the indices into one list 1622 | all_indices = idx_num_result + idx_num_result_inv 1623 | # compare if the two vector are duplicates 1624 | if set(all_indices) == set(list(range(len(p_set)))): 1625 | duplicate.append(pi_set) 1626 | 1627 | # remove duplicates from the main dict of all pi terms 1628 | for dup in duplicate: 1629 | self.__allpiterms.remove(dup) 1630 | return duplicate 1631 | 1632 | def generate_pi_terms(self): 1633 | ''' 1634 | Generates all the possible pi terms 1635 | ''' 1636 | self.__create_M() 1637 | 1638 | self.__create_symbolic_variables() 1639 | 1640 | self.__solve_null_spaces() 1641 | 1642 | self.__construct_symbolic_pi_terms() 1643 | 1644 | self.__rm_duplicated_powers() 1645 | 1646 | @property 1647 | def pi_terms(self): 1648 | ''' 1649 | :return: a list with all the symbolic dimensionless terms for all permutation of the dimensional Matrix M 1650 | ''' 1651 | return self.__allpiterms 1652 | 1653 | 1654 | def __Jupyter_print(self): 1655 | ''' print the rendered Latex format in Jupyter cell''' 1656 | for set_num, space in enumerate(self.__allpiterms): 1657 | latex_str= '\\text{Set }' 1658 | latex_str+='{}: \\quad'.format(set_num+1) 1659 | for num, term in enumerate(space): 1660 | latex_str += '\\pi_{} = '.format(num+1)+sp.latex(term) 1661 | latex_str += '\\quad' 1662 | display(Math(latex_str)) 1663 | display(Markdown('---')) 1664 | 1665 | def __tabulate_print(self,latex_string=False): 1666 | ''' print the dimensionless sets in a tabulated format''' 1667 | 1668 | latex_form = [] 1669 | for pi_set in self.__allpiterms: 1670 | latex_set = [] 1671 | for pi in pi_set: 1672 | if latex_string: 1673 | if latex_string: 1674 | latex_set.append(sp.latex(pi)) 1675 | else: 1676 | latex_set.append(pi) 1677 | else: 1678 | latex_set.append(pi) 1679 | latex_form.append(latex_set) 1680 | 1681 | num_of_pi_terms = len(latex_form[0]) 1682 | 1683 | headers = ['sets'] 1684 | for num in range(num_of_pi_terms): 1685 | headers.append('Pi {}'.format(num + 1)) 1686 | 1687 | for num, set in enumerate(latex_form): 1688 | set.insert(0, num + 1) 1689 | 1690 | print(tabulate(latex_form, headers=headers)) 1691 | 1692 | def print_all(self, latex_string=False): 1693 | ''' 1694 | print all the sets of dimensionless groups in latex or symbolic form. 1695 | :latex_string: optional boolean. If set to True the function will print the latex string of the 1696 | dimensionless groups. if set to False the function will print the symbolic form of the 1697 | dimensionless groups. 1698 | ''' 1699 | try: 1700 | ''' Try to render the latex in Jupyter cell''' 1701 | self.__Jupyter_print() 1702 | except: 1703 | ''' print the dimensionless sets in a tabulated format when in terminal session''' 1704 | self.__tabulate_print(latex_string) 1705 |
Ancestors (in MRO)
1713 |-
1714 |
- BuckinghamPi 1715 |
- builtins.object 1716 |
Static methods
1718 | 1719 |def __init__(
self)
1722 |Construct an instance of the BuckinghamPi theorem
def __init__(self): 1732 | ''' 1733 | Construct an instance of the BuckinghamPi theorem 1734 | ''' 1735 | self.__var_from_idx={} 1736 | self.__idx_from_var = {} 1737 | self.__variables={} 1738 | self.__sym_variables={} 1739 | self.__flagged_var = {'var_name':None, 'var_index':None,'selected':False} 1740 | self.__null_spaces = [] 1741 | self.__fundamental_vars_used = [] # list of fundamental variables being used 1742 |
def add_variable(
self, name, units, non_repeating=False)
1753 |Add variables to use for the pi-theorem 1759 | :param name: (string) name of the variable to be added 1760 | :param units: (string) expression of the independent physical variable expressed in terms of the k independent fundamental units. 1761 | :param non_repeating: (boolean) select a variable to belong to the non-repeating variables matrix. This will ensure that the selected variable 1762 | only shows up in one dimensionless group.
def add_variable(self, name: str, units: str, non_repeating=False): 1767 | ''' 1768 | Add variables to use for the pi-theorem 1769 | :param name: (string) name of the variable to be added 1770 | :param units: (string) expression of the independent physical variable expressed in terms of the k independent fundamental units. 1771 | :param non_repeating: (boolean) select a variable to belong to the non-repeating variables matrix. This will ensure that the selected variable 1772 | only shows up in one dimensionless group. 1773 | ''' 1774 | expr = self.__parse_expression(units) 1775 | self.__variables.update({name:expr}) 1776 | var_idx = len(list(self.__variables.keys()))-1 1777 | self.__var_from_idx[var_idx]= name 1778 | self.__idx_from_var[name] = var_idx 1779 | if non_repeating and (self.__flagged_var['selected'] == False): 1780 | self.__flagged_var['var_name'] = name 1781 | self.__flagged_var['var_index'] = var_idx 1782 | self.__flagged_var['selected'] = True 1783 | elif non_repeating and (self.__flagged_var['selected'] == True): 1784 | raise Exception("you cannot select more than one variable at a time to be a non_repeating.") 1785 |
def generate_pi_terms(
self)
1796 |Generates all the possible pi terms
def generate_pi_terms(self): 1806 | ''' 1807 | Generates all the possible pi terms 1808 | ''' 1809 | self.__create_M() 1810 | self.__create_symbolic_variables() 1811 | self.__solve_null_spaces() 1812 | self.__construct_symbolic_pi_terms() 1813 | self.__rm_duplicated_powers() 1814 |
def print_all(
self, latex_string=False)
1825 |print all the sets of dimensionless groups in latex or symbolic form. 1831 | :latex_string: optional boolean. If set to True the function will print the latex string of the 1832 | dimensionless groups. if set to False the function will print the symbolic form of the 1833 | dimensionless groups.
def print_all(self, latex_string=False): 1838 | ''' 1839 | print all the sets of dimensionless groups in latex or symbolic form. 1840 | :latex_string: optional boolean. If set to True the function will print the latex string of the 1841 | dimensionless groups. if set to False the function will print the symbolic form of the 1842 | dimensionless groups. 1843 | ''' 1844 | try: 1845 | ''' Try to render the latex in Jupyter cell''' 1846 | self.__Jupyter_print() 1847 | except: 1848 | ''' print the dimensionless sets in a tabulated format when in terminal session''' 1849 | self.__tabulate_print(latex_string) 1850 |
Instance variables
1858 |var fundamental_variables
1860 | 1861 | 1862 | 1863 | 1864 |:return: a list of the fundamental variables being used
var pi_terms
1871 | 1872 | 1873 | 1874 | 1875 |:return: a list with all the symbolic dimensionless terms for all permutation of the dimensional Matrix M
var variables
1882 | 1883 | 1884 | 1885 | 1886 |:return: a dict of the variables added by the user.