pchemlibrary 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: pchemlibrary
3
+ Version: 0.1.0
4
+ Summary: Library for teaching physical chemistry using Jupyter Notebooks
5
+ Author-email: Steven Neshyba <sneshyba@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: scipy
10
+ Requires-Dist: matplotlib
11
+ Requires-Dist: pint
12
+ Requires-Dist: plotly
13
+
14
+ This is a library of python functions that support Python-language codes for teaching physical chemistry.
15
+
16
+ # Installation
17
+ This has been packaged on PyPI. To install, run
18
+ ```sh
19
+ python -m pip install pchemlib
20
+ ```
21
+
22
+ # Usage
23
+ See examples in the examples folder.
@@ -0,0 +1,10 @@
1
+ This is a library of python functions that support Python-language codes for teaching physical chemistry.
2
+
3
+ # Installation
4
+ This has been packaged on PyPI. To install, run
5
+ ```sh
6
+ python -m pip install pchemlib
7
+ ```
8
+
9
+ # Usage
10
+ See examples in the examples folder.
@@ -0,0 +1 @@
1
+ from .pl import *
@@ -0,0 +1,499 @@
1
+ import numpy as np
2
+ from scipy.interpolate import RectBivariateSpline
3
+ import matplotlib.pyplot as plt
4
+ import plotly.graph_objects as go
5
+
6
+
7
+ def Statespace(xspecs,yspecs):
8
+ if hasattr(xspecs[0],'units'): x0 = xspecs[0].magnitude
9
+ else: x0 = xspecs[0]
10
+ if hasattr(xspecs[1],'units'): x1 = xspecs[1].magnitude
11
+ else: x1 = xspecs[1]
12
+ if hasattr(yspecs[0],'units'): y0 = yspecs[0].magnitude
13
+ else: y0 = yspecs[0]
14
+ if hasattr(yspecs[1],'units'): y1 = yspecs[1].magnitude
15
+ else: y1 = yspecs[1]
16
+
17
+ xarray = np.linspace(x0,x1,xspecs[2])
18
+ yarray = np.linspace(y0,y1,yspecs[2])
19
+ ygridtemp,xgridtemp = np.meshgrid(yarray,xarray)
20
+ xgrid = xgridtemp
21
+ ygrid = ygridtemp
22
+ return xgrid, ygrid
23
+
24
+ def plot_surface(Xgrid_in, Ygrid_in, Zgrid_in, color='gray', overlay=False, ax=0):
25
+ """
26
+ This plot_surface will be deprecated after 2023, to be replaced by plot_surface1
27
+ """
28
+
29
+ # Creates a surface plot in the handle myax
30
+
31
+ if overlay==False:
32
+ fig = plt.figure()
33
+ ax = plt.axes(projection='3d')
34
+ # ax = plt.figure().gca(projection='3d') # Set up a three dimensional graphics window
35
+
36
+ # This strips out units if necessary
37
+ if hasattr(Xgrid_in,'units'):
38
+ Xgrid = Xgrid_in.magnitude
39
+ else:
40
+ Xgrid = Xgrid_in
41
+
42
+ if hasattr(Ygrid_in,'units'):
43
+ Ygrid = Ygrid_in.magnitude
44
+ else:
45
+ Ygrid = Ygrid_in
46
+
47
+ if hasattr(Zgrid_in,'units'):
48
+ Zgrid = Zgrid_in.magnitude
49
+ else:
50
+ Zgrid = Zgrid_in
51
+
52
+ # Check to see if this is a scalar
53
+ if np.size(Zgrid) == 1:
54
+ Zgrid = Zgrid*np.ones(np.shape(Xgrid))
55
+
56
+ # Now plot
57
+ ax.plot_surface(Xgrid, Ygrid, Zgrid, color=color)
58
+
59
+ # Now return the handle
60
+ return ax
61
+
62
+
63
+ # def plot_surface1(Xgrid_in, Ygrid_in, Zgrid_in, color='gray', labellist=[], title=''):
64
+
65
+ # # Initiates a surface plot
66
+ # fig = plt.figure()
67
+ # ax = plt.axes(projection='3d')
68
+
69
+ # # This strips out units if necessary
70
+ # if hasattr(Xgrid_in,'units'):
71
+ # Xgrid = Xgrid_in.magnitude
72
+ # else:
73
+ # Xgrid = Xgrid_in
74
+
75
+ # if hasattr(Ygrid_in,'units'):
76
+ # Ygrid = Ygrid_in.magnitude
77
+ # else:
78
+ # Ygrid = Ygrid_in
79
+
80
+ # if hasattr(Zgrid_in,'units'):
81
+ # Zgrid = Zgrid_in.magnitude
82
+ # else:
83
+ # Zgrid = Zgrid_in
84
+
85
+ # # Now plot
86
+ # ax.plot_surface(Xgrid, Ygrid, Zgrid, color=color)
87
+
88
+ # if len(labellist) != 0:
89
+ # ax.set_xlabel(labellist[0])
90
+ # ax.set_ylabel(labellist[1])
91
+ # ax.set_zlabel(labellist[2])
92
+
93
+ # if title != '':
94
+ # ax.set_title(title)
95
+
96
+ # # Now return the handle
97
+ # return ax
98
+
99
+ def plot_surface1(Xgrid_in, Ygrid_in, Zgrid_in, color='gray', labellist=[], title='', zrange=[]):
100
+ fig = plot_surfaces(Xgrid_in, Ygrid_in, [Zgrid_in], colorlist=[color], labellist=labellist, titlelist=[title])
101
+ if len(zrange) != 0:
102
+ fig.update_layout(scene = dict(zaxis = dict(range=zrange)))
103
+ return fig
104
+
105
+ def plot_surfaces(Xgrid_in, Ygrid_in, Zgridlist_in, colorlist=[], labellist=[], titlelist=[]):
106
+
107
+ if len(colorlist) == 0:
108
+ print('colorlist has length zero')
109
+ colorlist = ['blues','greens','mint','reds']
110
+ else:
111
+ for i in range(len(colorlist)):
112
+ if colorlist[i] == 'plum': colorlist[i]='purples'
113
+ if colorlist[i] == 'blue': colorlist[i]='blues'
114
+ if colorlist[i] == 'green': colorlist[i]='greens'
115
+ if colorlist[i] == 'red': colorlist[i]='reds'
116
+ if colorlist[i] == 'purple': colorlist[i]='purples'
117
+
118
+ # This strips out units if necessary
119
+ if hasattr(Xgrid_in,'units'):
120
+ Xgrid = Xgrid_in.magnitude
121
+ else:
122
+ Xgrid = Xgrid_in
123
+
124
+ if hasattr(Ygrid_in,'units'):
125
+ Ygrid = Ygrid_in.magnitude
126
+ else:
127
+ Ygrid = Ygrid_in
128
+
129
+ if hasattr(Zgridlist_in[0],'units'):
130
+ Zgridlist = Zgridlist_in
131
+ for i in range(len(Zgridlist)):
132
+ Zgridlist[i] = Zgridlist_in[i].magnitude
133
+ else:
134
+ Zgridlist = Zgridlist_in
135
+
136
+ # Graphing all the surfaces
137
+ if len(Zgridlist) == 1:
138
+ fig = go.Figure(data=[
139
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[0], colorscale=colorlist[0], showscale=False)])
140
+
141
+ elif len(Zgridlist) == 2:
142
+ fig = go.Figure(data=[
143
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[1], colorscale=colorlist[1], showscale=False),
144
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[0], colorscale=colorlist[0], showscale=False)])
145
+
146
+ elif len(Zgridlist) == 3:
147
+ fig = go.Figure(data=[
148
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[2], colorscale=colorlist[2], showscale=False),
149
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[1], colorscale=colorlist[1], showscale=False),
150
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[0], colorscale=colorlist[0], showscale=False)])
151
+
152
+ elif len(Zgridlist) == 4:
153
+ fig = go.Figure(data=[
154
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[3], colorscale=colorlist[3], showscale=False),
155
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[2], colorscale=colorlist[2], showscale=False),
156
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[1], colorscale=colorlist[1], showscale=False),
157
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[0], colorscale=colorlist[0], showscale=False)])
158
+
159
+ elif len(Zgridlist) >= 5:
160
+ fig = go.Figure(data=[
161
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[4], colorscale=colorlist[4], showscale=False),
162
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[3], colorscale=colorlist[3], showscale=False),
163
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[2], colorscale=colorlist[2], showscale=False),
164
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[1], colorscale=colorlist[1], showscale=False),
165
+ go.Surface(x=Xgrid,y=Ygrid,z=Zgridlist[0], colorscale=colorlist[0], showscale=False)])
166
+ if len(Zgridlist) > 5:
167
+ print('From plot_multiple_surfaces: too many surfaces to overlap, sorry')
168
+
169
+
170
+ mytitlestring = ''
171
+ if len(titlelist) != 0:
172
+ if len(titlelist[0]) != 0:
173
+ # print('option 1')
174
+ for i in range(len(titlelist)):
175
+ mytitlestring += titlelist[i]+'='+str(colorlist[i])+' '
176
+
177
+ if len(labellist) != 0 and len(titlelist) == 0:
178
+ # print('option 2')
179
+ fig.update_layout(scene = dict(
180
+ xaxis_title=labellist[0],
181
+ yaxis_title=labellist[1],
182
+ zaxis_title=labellist[2]))
183
+
184
+ elif len(labellist) != 0 and len(titlelist) != 0:
185
+ # print('option 3')
186
+ fig.update_layout(scene = dict(
187
+ xaxis_title=labellist[0],
188
+ yaxis_title=labellist[1],
189
+ zaxis_title=labellist[2]),
190
+ title=mytitlestring)
191
+
192
+ elif len(labellist) == 0 and len(titlelist) != 0:
193
+ # print('option 4')
194
+ fig.update_layout(
195
+ title=mytitlestring)
196
+
197
+ fig.update_layout(autosize=True)
198
+ fig.update_yaxes(automargin=True)
199
+ mysize = 10
200
+ fig.update_scenes(xaxis = dict(tickfont=dict(size=mysize),titlefont=dict(size=mysize)))
201
+ fig.update_scenes(yaxis = dict(tickfont=dict(size=mysize),titlefont=dict(size=mysize)))
202
+ fig.update_scenes(zaxis = dict(tickfont=dict(size=mysize),titlefont=dict(size=mysize)))
203
+
204
+ return fig
205
+
206
+ def dF_dx(statespace,Fgrid):
207
+ # Returns the partial of F with respect to x (axis 0) holding y (axis 1) constant
208
+ xgrid = statespace[0]
209
+ ygrid = statespace[1]
210
+ dF = np.diff(Fgrid.magnitude,axis=0)
211
+ dx = np.diff(xgrid.magnitude,axis=0)
212
+ dF_dx = dF/dx
213
+ print('Shape of partial derivative =', np.shape(dF_dx))
214
+ try:
215
+ dF_dx *= Fgrid.units/xgrid.units
216
+ # print('Units of partial derivative =', dF_dx.units)
217
+ except:
218
+ print('No units')
219
+ xgridnew = xgrid[1:,:]
220
+ ygridnew = ygrid[1:,:]
221
+ return xgridnew, ygridnew, dF_dx
222
+
223
+ def dF_dy(statespace,Fgrid):
224
+ # Returns the partial of F with respect to y (axis 1) holding x (axis 0) constant
225
+ xgrid = statespace[0]
226
+ ygrid = statespace[1]
227
+ dF = np.diff(Fgrid.magnitude,axis=1)
228
+ dy = np.diff(ygrid.magnitude,axis=1)
229
+ dF_dy = dF/dy
230
+ print('Shape of partial derivative =', np.shape(dF_dy))
231
+ try:
232
+ dF_dy *= Fgrid.units/ygrid.units
233
+ #print('Units of partial derivative =', dF_dy.units)
234
+ except:
235
+ print('No units')
236
+ xgridnew = xgrid[:,1:]
237
+ ygridnew = ygrid[:,1:]
238
+ return xgridnew, ygridnew, dF_dy
239
+
240
+ def func_P_isotherm(V1,V2,n,R,T,AssignQuantity,P_units):
241
+ # Defines an isothermal expansion/contraction function
242
+ Varray = np.linspace(V1,V2)
243
+ Varray = AssignQuantity(Varray,V1.units)
244
+ Parray = n*R*T/Varray
245
+ Parray.ito(P_units)
246
+ return Varray, Parray
247
+
248
+ def func_P_adiabat(V1,V2,n,R,T1,C_V,AssignQuantity,P_units):
249
+ # Defines an adiabatic expansion/contraction function
250
+ V2array = np.linspace(V1,V2)
251
+ V2array = AssignQuantity(V2array,V2.units)
252
+ P1 = n*R*T1/V1
253
+ nR_over_C_V = n*R/C_V
254
+ P2array = P1*(V2array/V1)**(-nR_over_C_V-1)
255
+ P2array.ito(P_units)
256
+ return V2array, P2array
257
+
258
+ def CP_H2Ogas(T,AssignQuantity):
259
+ """ www.engineeringtoolbox.com/water-vapor-d_979.html """
260
+ m = AssignQuantity(0.0067,'J/mol/K^2')
261
+ CP0 = AssignQuantity(33.58,'J/mol/K')
262
+ T0 = AssignQuantity(300,'K')
263
+ CP = CP0 + m*(T-T0)
264
+ return CP
265
+
266
+ def CP_H2Oice(T,AssignQuantity):
267
+ """ www.liquisearch.com/heat_capacity/table_of_specific_heat_capacities """
268
+ CP = AssignQuantity(38.0,'J/mol/K')
269
+ return CP
270
+
271
+ def CP_H2Oliq(T,AssignQuantity):
272
+ """ https://webbook.nist.gov/cgi/cbook.cgi?ID=C7732185&Units=SI&Mask=2#Thermo-Condensed """
273
+ A = AssignQuantity(-203.606,'J/mol/K')
274
+ B = AssignQuantity(1523.290,'J/mol/K^2')
275
+ C = AssignQuantity(-3196.413,'J/mol/K^3')
276
+ D = AssignQuantity(2474.455,'J/mol/K^4')
277
+ E = AssignQuantity(3.855326,'J/mol K')
278
+ t = T/1000
279
+ CP = A + B*t + C*t**2 + D*t**3 + E/t**2
280
+ return CP
281
+
282
+ def Integrator_new(statespace,dF_dx,dF_dy,AssignQuantity,SState=[],Units=[],axis=0):
283
+ """
284
+ Integrates a differential equation of state to produce F(x,y)
285
+ Assumes quantities have units
286
+ """
287
+ # from scipy.interpolate import RectBivariateSpline
288
+ # from scipy import interpolate
289
+ # This used to be called Integrator_pint
290
+
291
+ dF_dx_local = dF_dx.to_base_units(); #print('dF_dx.units', dF_dx_local.units)
292
+ dF_dy_local = dF_dy.to_base_units(); #print('dF_dy.units', dF_dy_local.units)
293
+
294
+ xgrid = statespace[0]
295
+ xgrid_local = xgrid.to_base_units()
296
+ ygrid = statespace[1]
297
+ ygrid_local = ygrid.to_base_units()
298
+
299
+ dx = xgrid_local[1,0]-xgrid_local[0,0]
300
+ dy = ygrid_local[0,1]-ygrid_local[0,0]
301
+
302
+ nx,ny = np.shape(xgrid)
303
+ Fgrid = np.zeros(np.shape(xgrid))
304
+
305
+ # If we're getting scalars, convert them
306
+ if np.size(dF_dx_local) == 1:
307
+ dF_dx_local = dF_dx_local*np.ones(np.shape(xgrid_local))
308
+ if np.size(dF_dy) == 1:
309
+ dF_dy_local = dF_dy_local*np.ones(np.shape(xgrid_local))
310
+
311
+ # Branch according to which axis to integrate along first
312
+ if axis==0:
313
+ integral_along_x = np.cumsum(dF_dx_local[:,0])*dx
314
+ for i in range(nx):
315
+ integral_along_y = np.cumsum(dF_dy_local[i,:])*dy
316
+ integral_along_y += integral_along_x[i]
317
+ Fgrid[i,:] = integral_along_y.magnitude
318
+ else:
319
+ integral_along_y = np.cumsum(dF_dy_local[0,:])*dy
320
+ for i in range(ny):
321
+ integral_along_x = np.cumsum(dF_dx_local[:,i])*dx
322
+ integral_along_x += integral_along_y[i]
323
+ Fgrid[:,i] = integral_along_x.magnitude
324
+
325
+ # Apply an offset if desired
326
+ debugging = False
327
+ Fgrid = AssignQuantity(Fgrid,dF_dx_local.units*dx.units)
328
+ if debugging: print('Fgrid.units:', Fgrid.units)
329
+ if len(SState) != 0:
330
+ SState_x = SState[0]; SState_x.ito_base_units()
331
+ if debugging: print('SState_x:', SState_x)
332
+ SState_y = SState[1]; SState_y.ito_base_units()
333
+ if debugging: print('SState_y:', SState_y)
334
+ SState_F = SState[2]; SState_F.ito_base_units()
335
+ if debugging: print('SState_F:', SState_F)
336
+ if debugging: print('Origin', xgrid[0,0],ygrid[0,0])
337
+ if debugging: print('Standard states', SState_x,SState_y)
338
+
339
+ # This shouldn't have to be done, but I can't get the interpolator to work properly
340
+ ix_SS = nx-1 # Just a starting guess, it'll get over-ridden below
341
+ last_deviation = (xgrid[ix_SS,0] - SState_x)**2
342
+ for ix in range(nx):
343
+ deviation = (xgrid[ix,0] - SState_x)**2
344
+ if (deviation < last_deviation):
345
+ last_deviation = deviation
346
+ ix_SS = ix
347
+ iy_SS = ny-1 # Just a starting guess, it'll get over-ridden below
348
+ last_deviation = (ygrid[0,iy_SS] - SState_y)**2
349
+ for iy in range(ny):
350
+ deviation = (ygrid[0,iy] - SState_y)**2
351
+ if (deviation < last_deviation):
352
+ last_deviation = deviation
353
+ iy_SS = iy
354
+
355
+ # Find the value to be subtracted away
356
+ Original_Fgrid_at_standard_state = np.squeeze(Fgrid[ix_SS,iy_SS])
357
+ if debugging: print('Indices closest to standard state', ix_SS, iy_SS)
358
+ if debugging: print('Original Fgrid at standard state', Original_Fgrid_at_standard_state)
359
+
360
+ # Create the new Fgrid
361
+ new_Fgrid = Fgrid -Original_Fgrid_at_standard_state +SState_F
362
+
363
+ if len(Units) != 0:
364
+ new_Fgrid.ito(Units)
365
+
366
+ return(new_Fgrid)
367
+
368
+
369
+ def Integrator(statespace,dF_dx,dF_dy,AssignQuantity,SState=[],Units=[],axis=0):
370
+ """
371
+ Integrates a differential equation of state to produce F(x,y)
372
+ """
373
+ from scipy.interpolate import RectBivariateSpline
374
+ xgrid = statespace[0]
375
+ ygrid = statespace[1]
376
+ xarray = xgrid[:,0]; dx = (xarray[1]-xarray[0]); #print('dx=',dx)
377
+ yarray = ygrid[0,:]; dy = (yarray[1]-yarray[0]); #print('dy=',dy)
378
+ Fgrid = np.zeros(np.shape(xgrid))
379
+
380
+ # Branch according to which axis to integrate along first
381
+ if axis==0:
382
+ integral_along_x = np.cumsum(dF_dx[:,0])*dx
383
+ for i in range(len(xarray)):
384
+ integral_along_y = np.cumsum(dF_dy[i,:])*dy
385
+ integral_along_y += integral_along_x[i]
386
+ Fgrid[i,:] = integral_along_y
387
+ else:
388
+ integral_along_y = np.cumsum(dF_dy[0,:])*dy
389
+ for i in range(len(yarray)):
390
+ integral_along_x = np.cumsum(dF_dx[:,i])*dx
391
+ integral_along_x += integral_along_y[i]
392
+ Fgrid[:,i] = integral_along_x
393
+
394
+ # Assign units if desired
395
+ if len(Units) != 0:
396
+ print('Assigning units:', Units)
397
+ Fgrid = AssignQuantity(Fgrid,Units)
398
+ else:
399
+ Fgrid = AssignQuantity(Fgrid,integral_along_y.units)
400
+
401
+ # Apply an offset if desired
402
+ if len(SState) != 0:
403
+ SState_x = SState[0]
404
+ SState_y = SState[1]
405
+ SState_F = SState[2]
406
+ Fgrid_interpolater = RectBivariateSpline(xgrid[:,0], ygrid[0,:], Fgrid)
407
+ Fgrid_at_standard_state = Fgrid_interpolater(SState_x,SState_y)
408
+ Fgrid_at_standard_state = AssignQuantity(Fgrid_at_standard_state,SState_F.units)
409
+ Fgrid -= Fgrid_at_standard_state
410
+ Fgrid += SState_F
411
+
412
+ return(Fgrid)
413
+
414
+ def StateSpaceInterpolator(statespace,nxarray,nyarray,Fgrid,AssignQuantity=0):
415
+ if type(AssignQuantity) == type:
416
+ #print('I think it is a function')
417
+ useAssignQuantity = True
418
+ else:
419
+ useAssignQuantity = False
420
+ xgrid = statespace[0]
421
+ ygrid = statespace[1]
422
+ Fgrid_interpolater = RectBivariateSpline(xgrid[:,0], ygrid[0,:], Fgrid)
423
+ if np.size(nxarray) == 1:
424
+ nxarray = [nxarray]
425
+ nyarray = [nyarray]
426
+ result = []
427
+ for i in range(len(nxarray)):
428
+ result.append(Fgrid_interpolater(nxarray[i],nyarray[i]))
429
+ result = np.squeeze(result)
430
+ if useAssignQuantity:
431
+ result = AssignQuantity(result,Fgrid.units)
432
+ return np.squeeze(result)
433
+
434
+ def trapz(integrand,x,AssignQuantity=0):
435
+ # Uses numpy's trapz, but with units
436
+ try:
437
+ integrand.units
438
+ result = np.trapz(integrand.magnitude,x.magnitude)
439
+ result = AssignQuantity(result,integrand.units*x.units)
440
+ return result
441
+ except:
442
+ print('Integrating without units')
443
+ result = np.trapz(integrand,x)
444
+ return result
445
+
446
+ # These (drawbox_xx and plot3d) are from Chem 341; plot3d should be replaced by plot_surface1
447
+
448
+ # Draw the box (clumsily)
449
+ from itertools import product, combinations
450
+ def drawbox_xx(xinit,xfinal,y,z,fig=[]):
451
+ if np.size(fig) == 0:
452
+ fig = plt.figure()
453
+ ax = fig.gca(projection='3d')
454
+ ax.set_box_aspect(aspect = (xinit,y,z))
455
+ rext = xfinal/xinit
456
+ r = [0, 1]
457
+ for s, e in combinations(np.array(list(product(r, r, r))), 2):
458
+ if np.sum(np.abs(s-e)) == r[1]-r[0]:
459
+ ax.plot3D(*zip(s, e), color="b")
460
+ ax.plot3D([1.0, rext],[0, 0],[0, 0],color='g')
461
+ ax.plot3D([1.0, rext],[1, 1],[1, 1],color='g')
462
+ ax.plot3D([1.0, rext],[0, 0],[1, 1],color='g')
463
+ ax.plot3D([1.0, rext],[1, 1],[0, 0],color='g')
464
+ ax.plot3D([rext, rext],[0, 1],[0, 0],color='g')
465
+ ax.plot3D([rext, rext],[0, 0],[0, 1],color='g')
466
+ ax.plot3D([rext, rext],[0, 1],[1, 1],color='g')
467
+ ax.plot3D([rext, rext],[1, 1],[0, 1],color='g')
468
+ ax.set_xticks([])
469
+ ax.set_yticks([])
470
+ ax.set_zticks([])
471
+ ax.set_xlabel('x')
472
+ ax.set_ylabel('y')
473
+ ax.set_zlabel('z')
474
+ return fig
475
+
476
+ # Plotting in 3d
477
+ def plot3d(xgrid,ygrid,zgrid,xaxis_title='x',yaxis_title='y',zaxis_title='z'):
478
+ fig = go.Figure(data=go.Surface(x=xgrid,y=ygrid,z=zgrid))
479
+ fig.update_layout(scene = dict(
480
+ xaxis_title=xaxis_title,
481
+ yaxis_title=yaxis_title,
482
+ zaxis_title=zaxis_title))
483
+ fig.show()
484
+
485
+ def f_sigmoid(f1, f2, T, AssignQuantity, T_interval_magnitude=3, T_transition_magnitude=0):
486
+ if T_transition_magnitude == 0:
487
+ T1 = np.max(T)
488
+ T2 = np.min(T)
489
+ Tmid = (T2+T1)/2
490
+ T_transition = AssignQuantity(Tmid,'K')
491
+ else:
492
+ T_transition = AssignQuantity(T_transition_magnitude,'K')
493
+ T_interval = AssignQuantity(T_interval_magnitude,'K')
494
+ sigmoid_arg = (T-T_transition)/T_interval
495
+ sigmoid = 1 - 1.0/(1.0 + np.exp(-sigmoid_arg))
496
+ sigmoid_min = sigmoid[0,0]; #print(sigmoid_min)
497
+ sigmoid_max = sigmoid[-1,0]; #print(sigmoid_max)
498
+ f = (sigmoid-sigmoid_min)*(f2-f1)/(sigmoid_max-sigmoid_min)+f1
499
+ return f
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: pchemlibrary
3
+ Version: 0.1.0
4
+ Summary: Library for teaching physical chemistry using Jupyter Notebooks
5
+ Author-email: Steven Neshyba <sneshyba@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: scipy
10
+ Requires-Dist: matplotlib
11
+ Requires-Dist: pint
12
+ Requires-Dist: plotly
13
+
14
+ This is a library of python functions that support Python-language codes for teaching physical chemistry.
15
+
16
+ # Installation
17
+ This has been packaged on PyPI. To install, run
18
+ ```sh
19
+ python -m pip install pchemlib
20
+ ```
21
+
22
+ # Usage
23
+ See examples in the examples folder.
@@ -0,0 +1,9 @@
1
+ README.md
2
+ pyproject.toml
3
+ pchemlibrary/__init__.py
4
+ pchemlibrary/pl.py
5
+ pchemlibrary.egg-info/PKG-INFO
6
+ pchemlibrary.egg-info/SOURCES.txt
7
+ pchemlibrary.egg-info/dependency_links.txt
8
+ pchemlibrary.egg-info/requires.txt
9
+ pchemlibrary.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ numpy
2
+ scipy
3
+ matplotlib
4
+ pint
5
+ plotly
@@ -0,0 +1,3 @@
1
+ dist
2
+ examples_of_python_notebooks
3
+ pchemlibrary
@@ -0,0 +1,15 @@
1
+ [project]
2
+ name = "pchemlibrary"
3
+ version = "0.1.0"
4
+ description = "Library for teaching physical chemistry using Jupyter Notebooks"
5
+ authors = [{ name = "Steven Neshyba", email = "sneshyba@gmail.com" }]
6
+ readme = "README.md"
7
+ requires-python = ">=3.8"
8
+ dependencies = ['numpy', 'scipy', 'matplotlib', 'pint', 'plotly']
9
+
10
+ [build-system]
11
+ requires = ["setuptools>=61.0", "wheel"]
12
+ build-backend = "setuptools.build_meta"
13
+
14
+ [tool.setuptools.packages.find]
15
+ where = ["."]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+