def single_phase_v(self, P, T=None, print_results=True, get_density=False): if isinstance(T, float): self.temp = T if isinstance(P, float) or isinstance(P, int): Pv, vle = self.vapour_pressure(temperature=T, get_volume=True) v_init = vle[0] if P > Pv else vle[1] getv = least_squares(self.__getp, v_init, kwargs={"targetP": P}) if print_results: print(getv) return getv.x[0] if get_density == False else (getv.x[0], 1 / getv.x[0]) mt.checkerr(isinstance(P, np.ndarray), "Use float/int or ndarray for pressure inputs") varr = np.zeros(np.size(P)) for i in range(len(P)): Pv, vle = self.vapour_pressure(temperature=T, get_volume=True) v_init = vle[0] if P[i] > Pv else vle[1] getv = least_squares(self.__getp, v_init, kwargs={"targetP": P[i]}) varr[i] = getv.x[0] return varr if get_density == False else (varr, 1. / varr)
def set_angle(self, other, angle): mt.checkerr( isinstance(angle, tuple) and len(angle) == 3, "Use 3d vector tuple to specify angle") if other in self.connectedTo: self.connectedTo[other] = angle other.connectedTo[self] = mt.inv_angle(angle)
def __init__(self, mass, *args): self.gtypes = {} for group in args: mt.checkerr( isinstance(group, GroupType), "Use GroupType object to specify groups used as optional arguments" ) self.gtypes[group] = 0 self.groups = {} self.mass = mass
def connect(self, other, angle=None): mt.checkerr(isinstance(other, Group), "Groups can only connect to other groups") mt.checkerr( angle == None or (isinstance(angle, tuple) and len(angle) == 3), "Either don't specify angle, or use 3d vector tuple") self.connections = self.connections + 1 self.connectedTo[other] = angle if not other.connected(self): other.connect(self)
def add_moles(self, **kwargs): for comp in kwargs: mt.checkerr(comp in self.comps, "Component name {} is not in system".format(comp)) mt.checkerr(isinstance(kwargs[comp], int), "Int values for components only") for comp in kwargs: self.moles[comp] = self.moles[comp] + kwargs[comp] for comp in self.molfrac: self.molfrac[comp] = self.moles[comp] / self.__moltol()
def p_rho_isotherm(self, nden, temperature=None): ''' nden in mol/m3 ''' if isinstance(temperature, float): self.temp = temperature mt.checkerr(isinstance(nden, float), "Use floats for rho") volume = self.__moltol() / (cst.Na * nden * pow(cst.nmtom, 3)) self.volume = Var(volume) A = self.helmholtz() result = -derivative(A, self.volume) / pow(cst.nmtom, 3) # Reset system back to float self.volume = volume return result
def __init__(self, temperature=293, volume=1000, **kwargs): for comp in kwargs: mt.checkerr( isinstance(kwargs[comp], Component), "Use Component object to specify groups used, with format CompName = Component obj" ) self.comps = kwargs self.moles = {} self.molfrac = {} for comp in self.comps: self.moles[comp] = 0 self.molfrac[comp] = 0 self.temp = temperature # K self.volume = volume # nm^3 self.pressure = 1 # bar (temporarily useless) self.sdt = 1
def add_comp(self, **kwargs): for comp in kwargs: mt.checkerr( isinstance(kwargs[comp], Component), "Use Component object to specify groups used, with format CompName = Component obj" ) for comp in kwargs: mt.checkwarn( kwargs[comp] in self.comps.values(), "Component object already exist, {} not added".format(comp)) mt.checkwarn(comp in self.comps, "Component name taken, {} not added".format(comp)) if (comp not in self.comps) and (kwargs[comp] not in self.comps.values()): self.comps[comp] = kwargs[comp] self.moles[comp] = 0 self.molfrac[comp] = 0
def p_v_isotherm(self, volume, temperature=None, gibbs=False): ''' Get pressure profile from volume inputs. Volume in m3 per mol ''' if isinstance(temperature, float) or isinstance(temperature, int): self.temp = temperature mt.checkerr( isinstance(volume, float) or isinstance(volume, np.ndarray), "Use floats or numpy array for volume") volume = self.__moltol() * volume / (cst.Na * pow(cst.nmtom, 3)) Var.set_order(1) # Case single volume value if isinstance(volume, float): self.volume = Var(volume) A = self.helmholtz() result = -derivative(A, self.volume, order=1) / pow(cst.nmtom, 3) # Reset system back to float self.volume = volume return result # Case numpy array old_v = self.volume vlen = np.size(volume) P = np.zeros(vlen) if gibbs: G = np.zeros(vlen) print('=' * 5, f'Pv Isotherm data from {vlen:5d} points', '=' * 5) tenp = vlen // 10 for i in range(vlen): self.volume = Var(volume[i]) A = self.helmholtz() P[i] = -derivative(A, self.volume) / pow(cst.nmtom, 3) if gibbs: G[i] = (A.value + P[i] * self.volume.value * pow(cst.nmtom, 3)) / self.__moltol() if (i + 1) % tenp == 0: print(f'Progress at {(i+1)//tenp * 10:3d}%') # Reset system back to float self.volume = old_v return (P, G) if gibbs else P
def add_group(self, name, gtype): mt.checkerr(isinstance(gtype, GroupType), "Group type invalid, use GroupType object") mt.checkerr(isinstance(name, str), "Use str for name") mt.checkerr(name not in self.groups, "Group name taken") if (gtype not in self.gtypes): self.gtypes[gtype] = 0 self.groups[name] = Group(gtype) self.gtypes[gtype] = self.gtypes[gtype] + 1 return self.groups[name]
def quick_set(self, *args): gtypel = [] numl = [] for arg in args: mt.checkerr( isinstance(arg, tuple) or isinstance(arg, list), "Use iterable tuple or list for components and no. of molecules" ) mt.checkerr(isinstance(arg[0], GroupType), "First element of iterable must be of GroupType") mt.checkerr(isinstance(arg[1], int), "Second element of iterable must be of int") gtypel.append(arg[0]) numl.append(arg[1]) names = [] count = 1 groupsAdding = sum(numl) for i in range(groupsAdding): name = 'G{:03d}'.format(count) while (name in self.groups) or (name in names): count = count + 1 name = 'G{:03d}'.format(count) names.append(name) faults = 0 for i in range(len(gtypel)): if isinstance(gtypel[i], GroupType): for j in range(numl[i]): self.add_group(names[sum(numl[0:i]) + j - faults], gtypel[i]) else: print("Not GroupType obj error, groups not added") faults = faults + numl[i] print('{:3d} groups were to be added, {:3d} groups were added'.format( groupsAdding, groupsAdding - faults)) return self
def quick_set(self, *args): complist = [] molelist = [] for arg in args: mt.checkerr( isinstance(arg, tuple) or isinstance(arg, list), "Use iterable tuple or list for quick_set") mt.checkerr(isinstance(arg[0], Component), "First element of iterable must be of Component type") mt.checkerr(isinstance(arg[1], int), "Second element of iterable must be of int type") complist.append(arg[0]) molelist.append(arg[1]) num = [] count = 1 for i in range(len(complist)): name = 'COMP{:03d}'.format(count) while (name in self.comps) or (name in num): count = count + 1 name = 'COMP{:03d}'.format(count) num.append(name) faults = 0 for i in range(len(complist)): if (complist[i] not in self.comps.values()): self.comps[num[i - faults]] = complist[i] self.moles[num[i - faults]] = molelist[i] self.molfrac[num[i - faults]] = 0 else: print("Component already in system, molecules not added") faults = faults + 1 for comp in self.molfrac: self.molfrac[comp] = self.moles[comp] / self.__moltol() return self
def connect(self, name1, name2, angle=None): mt.checkerr(name1 in self.groups and name2 in self.groups, "Name missing from list of groups") self.groups[name1].connect(self.groups[name2], angle)