pyphyschemtools 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
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.
- pyphyschemtools/.__init__.py.swp +0 -0
- pyphyschemtools/.ipynb_checkpoints/Chem3D-checkpoint.py +835 -0
- pyphyschemtools/.ipynb_checkpoints/PeriodicTable-checkpoint.py +294 -0
- pyphyschemtools/.ipynb_checkpoints/aithermo-checkpoint.py +349 -0
- pyphyschemtools/.ipynb_checkpoints/core-checkpoint.py +120 -0
- pyphyschemtools/.ipynb_checkpoints/spectra-checkpoint.py +471 -0
- pyphyschemtools/.ipynb_checkpoints/survey-checkpoint.py +1048 -0
- pyphyschemtools/.ipynb_checkpoints/sympyUtilities-checkpoint.py +51 -0
- pyphyschemtools/.ipynb_checkpoints/tools4AS-checkpoint.py +964 -0
- pyphyschemtools/Chem3D.py +12 -8
- pyphyschemtools/ML.py +6 -4
- pyphyschemtools/PeriodicTable.py +9 -4
- pyphyschemtools/__init__.py +3 -3
- pyphyschemtools/aithermo.py +5 -6
- pyphyschemtools/core.py +7 -6
- pyphyschemtools/spectra.py +78 -58
- pyphyschemtools/survey.py +0 -449
- pyphyschemtools/sympyUtilities.py +9 -9
- pyphyschemtools/tools4AS.py +12 -8
- {pyphyschemtools-0.1.0.dist-info → pyphyschemtools-0.1.1.dist-info}/METADATA +2 -2
- {pyphyschemtools-0.1.0.dist-info → pyphyschemtools-0.1.1.dist-info}/RECORD +29 -20
- /pyphyschemtools/{icons-logos-banner → icons_logos_banner}/Logo_pyPhysChem_border.svg +0 -0
- /pyphyschemtools/{icons-logos-banner → icons_logos_banner}/__init__.py +0 -0
- /pyphyschemtools/{icons-logos-banner → icons_logos_banner}/logo.png +0 -0
- /pyphyschemtools/{icons-logos-banner → icons_logos_banner}/tools4pyPC_banner.png +0 -0
- /pyphyschemtools/{icons-logos-banner → icons_logos_banner}/tools4pyPC_banner.svg +0 -0
- {pyphyschemtools-0.1.0.dist-info → pyphyschemtools-0.1.1.dist-info}/WHEEL +0 -0
- {pyphyschemtools-0.1.0.dist-info → pyphyschemtools-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {pyphyschemtools-0.1.0.dist-info → pyphyschemtools-0.1.1.dist-info}/top_level.txt +0 -0
pyphyschemtools/survey.py
CHANGED
|
@@ -597,452 +597,3 @@ class SurveyApp:
|
|
|
597
597
|
f"<code>{os.path.abspath(self.summary_dir)}</code>"
|
|
598
598
|
))
|
|
599
599
|
|
|
600
|
-
############################################################
|
|
601
|
-
# Absorption spectra
|
|
602
|
-
############################################################
|
|
603
|
-
|
|
604
|
-
import numpy as np
|
|
605
|
-
import matplotlib.pyplot as plt
|
|
606
|
-
import scipy.constants as sc
|
|
607
|
-
|
|
608
|
-
class SpectrumSimulator:
|
|
609
|
-
|
|
610
|
-
def __init__(self, sigma_ev=0.3, plotWH=(12,8), \
|
|
611
|
-
fontSize_axisText=14, fontSize_axisLabels=14, fontSize_legends=12,
|
|
612
|
-
fontsize_peaks=12,
|
|
613
|
-
colorS='#3e89be',colorVT='#469cd6'
|
|
614
|
-
):
|
|
615
|
-
"""
|
|
616
|
-
Initializes the spectrum simulator
|
|
617
|
-
|
|
618
|
-
Args:
|
|
619
|
-
- sigma_ev (float): Gaussian half-width at half-maximum in electron-volts (eV).
|
|
620
|
-
Default is 0.3 eV (GaussView default is 0.4 eV).
|
|
621
|
-
- plotWH (tuple(int,int)): Width and Height of the matplotlib figures in inches. Default is (12,8).
|
|
622
|
-
- colorS: color of the simulated spectrum (default ='#3e89be')
|
|
623
|
-
- colorVT: color of the vertical transition line (default = '#469cd6')
|
|
624
|
-
|
|
625
|
-
Returns:
|
|
626
|
-
None: This method initializes the instance attributes.
|
|
627
|
-
Calculates:
|
|
628
|
-
- sigmanm = half-width of the Gaussian band, in nm
|
|
629
|
-
"""
|
|
630
|
-
self.sigma_ev = sigma_ev
|
|
631
|
-
# Conversion constante eV -> nm sigma
|
|
632
|
-
self.ev2nm_const = (sc.h * sc.c) * 1e9 / sc.e
|
|
633
|
-
self.sigmanm = self.ev2nm_const / self.sigma_ev
|
|
634
|
-
self.plotW = plotWH[0]
|
|
635
|
-
self.plotH = plotWH[1]
|
|
636
|
-
self.colorS = colorS
|
|
637
|
-
self.colorVT = colorVT
|
|
638
|
-
self.fig = None
|
|
639
|
-
self.graph = None
|
|
640
|
-
self.fontSize_axisText = fontSize_axisText
|
|
641
|
-
self.fontSize_axisLabels = fontSize_axisLabels
|
|
642
|
-
self.fontSize_legends = fontSize_legends
|
|
643
|
-
self.fontsize_peaks = fontsize_peaks
|
|
644
|
-
|
|
645
|
-
print(f"sigma = {sigma_ev} eV -> sigmanm = {self.sigmanm:.1f} nm")
|
|
646
|
-
|
|
647
|
-
def _initializePlot(self):
|
|
648
|
-
fig, graph = plt.subplots(figsize=(self.plotW,self.plotH))
|
|
649
|
-
plt.subplots_adjust(wspace=0)
|
|
650
|
-
plt.xticks(fontsize=self.fontSize_axisText,fontweight='bold')
|
|
651
|
-
plt.yticks(fontsize=self.fontSize_axisText,fontweight='bold')
|
|
652
|
-
return fig, graph
|
|
653
|
-
|
|
654
|
-
def _calc_epsiG(self,lambdaX,lambdai,fi):
|
|
655
|
-
'''
|
|
656
|
-
calculates a Gaussian band shape around a vertical transition
|
|
657
|
-
input:
|
|
658
|
-
- lambdaX = wavelength variable, in nm
|
|
659
|
-
- lambdai = vertical excitation wavelength for i_th state, in nm
|
|
660
|
-
- fi = oscillator strength for state i (dimensionless)
|
|
661
|
-
output :
|
|
662
|
-
molar absorption coefficient, in L mol-1 cm-1
|
|
663
|
-
'''
|
|
664
|
-
import scipy.constants as sc
|
|
665
|
-
import numpy as np
|
|
666
|
-
c = sc.c*1e2 #cm-1
|
|
667
|
-
NA = sc.N_A #mol-1
|
|
668
|
-
me = sc.m_e*1000 #g
|
|
669
|
-
e = sc.e*sc.c*10 #elementary charge in esu
|
|
670
|
-
pf = np.sqrt(np.pi)*e**2*NA/(1000*np.log(10)*c**2*me)
|
|
671
|
-
nubarX = 1e7 / lambdaX # nm to cm-1
|
|
672
|
-
nubari = 1e7 / lambdai
|
|
673
|
-
sigmabar = 1e7 / self.sigmanm
|
|
674
|
-
epsi = pf * (fi / sigmabar) * np.exp(-((nubarX - nubari)/sigmabar)**2)
|
|
675
|
-
return epsi
|
|
676
|
-
|
|
677
|
-
def _Absorbance(self,eps,opl,cc):
|
|
678
|
-
'''
|
|
679
|
-
Calculates the Absorbance with the Beer-Lambert law
|
|
680
|
-
input:
|
|
681
|
-
- eps = molar absorption coefficient, in L mol-1 cm-1
|
|
682
|
-
- opl = optical path length, in cm
|
|
683
|
-
- cc = concentration of the attenuating species, in mol.L-1
|
|
684
|
-
output :
|
|
685
|
-
Absorbance, A (dimensionless)
|
|
686
|
-
'''
|
|
687
|
-
return eps*opl*cc
|
|
688
|
-
|
|
689
|
-
def _sumStatesWithGf(self,wavel,wavelTAB,feTAB):
|
|
690
|
-
'''
|
|
691
|
-
'''
|
|
692
|
-
import numpy as np
|
|
693
|
-
sumInt = np.zeros(len(wavel))
|
|
694
|
-
for l in wavel:
|
|
695
|
-
for i in range(len(wavelTAB)):
|
|
696
|
-
sumInt[np.argwhere(l==wavel)[0][0]] += self._calc_epsiG(l,wavelTAB[i],feTAB[i])
|
|
697
|
-
return sumInt
|
|
698
|
-
|
|
699
|
-
def _FindPeaks(self,sumInt,height,prom=1):
|
|
700
|
-
'''
|
|
701
|
-
Finds local maxima within the spectrum based on height and prominence.
|
|
702
|
-
|
|
703
|
-
Prominence is crucial when switching between linear and logarithmic scales:
|
|
704
|
-
- In Linear mode: A large prominence (e.g., 1 to 1000) filters out noise.
|
|
705
|
-
- In Log mode: Data is compressed into a range of ~0 to 5. A large
|
|
706
|
-
prominence will 'hide' real peaks. A smaller value (0.01 to 0.1)
|
|
707
|
-
is required to detect shoulders and overlapping bands.
|
|
708
|
-
|
|
709
|
-
Input:
|
|
710
|
-
- sumInt: Array of intensities (Epsilon or Absorbance).
|
|
711
|
-
- height: Minimum height a peak must reach to be considered.
|
|
712
|
-
- prom: Required vertical distance between the peak and its lowest contour line.
|
|
713
|
-
|
|
714
|
-
Returns:
|
|
715
|
-
- PeakIndex: Indices of the detected peaks in the wavelength array.
|
|
716
|
-
- PeakHeight: The intensity values at these peak positions.
|
|
717
|
-
'''
|
|
718
|
-
from scipy.signal import find_peaks
|
|
719
|
-
peaks = find_peaks(sumInt, height = height, threshold = None, distance = 1, prominence=prom)
|
|
720
|
-
PeakIndex = peaks[0]
|
|
721
|
-
# Check if 'peak_heights' exists in the properties dictionary
|
|
722
|
-
if 'peak_heights' in peaks[1]:
|
|
723
|
-
PeakHeight = peaks[1]['peak_heights']
|
|
724
|
-
else:
|
|
725
|
-
# If height=None, we extract values manually from the input data
|
|
726
|
-
PeakHeight = sumInt[PeakIndex]
|
|
727
|
-
return PeakIndex,PeakHeight
|
|
728
|
-
|
|
729
|
-
def _FindShoulders(self, data, tP):
|
|
730
|
-
'''
|
|
731
|
-
###not working
|
|
732
|
-
Detects shoulders using the second derivative.
|
|
733
|
-
A shoulder appears as a peak in the negative second derivative.
|
|
734
|
-
|
|
735
|
-
Note on scales:
|
|
736
|
-
- If ylog is True: data should be log10(sumInt) and tP should be log10(tP).
|
|
737
|
-
The second derivative on log data is much more sensitive to subtle
|
|
738
|
-
inflection points in weak transitions (like n -> pi*).
|
|
739
|
-
- If ylog is False: data is linear sumInt and tP is linear.
|
|
740
|
-
|
|
741
|
-
Returns:
|
|
742
|
-
- shoulder_idx (ndarray): Array of indices where shoulders were found.
|
|
743
|
-
- shoulder_heights (ndarray): The intensity values at these positions
|
|
744
|
-
extracted from the input data.
|
|
745
|
-
'''
|
|
746
|
-
import numpy as np
|
|
747
|
-
# Calculate the second derivative (rate of change of the slope)
|
|
748
|
-
d2 = np.gradient(np.gradient(data))
|
|
749
|
-
|
|
750
|
-
# We search for peaks in the opposite of the second derivative (-d2).
|
|
751
|
-
# A local maximum in -d2 corresponds to a point of maximum curvature
|
|
752
|
-
# (inflection), which identifies a shoulder.
|
|
753
|
-
# We use a very low prominence threshold to capture subtle inflections.
|
|
754
|
-
shoulder_idx, _ = self._FindPeaks(-d2, height=None, prom=0.0001)
|
|
755
|
-
shoulder_heights = data[shoulder_idx]
|
|
756
|
-
print(shoulder_idx, shoulder_heights )
|
|
757
|
-
|
|
758
|
-
return shoulder_idx, shoulder_heights
|
|
759
|
-
|
|
760
|
-
def _pickPeak(self,wavel,peaksIndex,peaksH,color,\
|
|
761
|
-
shift=500,height=500,posAnnotation=200, ylog=False):
|
|
762
|
-
'''
|
|
763
|
-
Annotates peaks with a small vertical tick and the wavelength value.
|
|
764
|
-
Adjusts offsets based on whether the plot is in log10 scale or linear.
|
|
765
|
-
In log mode, peaksH must already be log10 values.
|
|
766
|
-
'''
|
|
767
|
-
s=shift
|
|
768
|
-
h=height
|
|
769
|
-
a=posAnnotation
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
for i in range(len(peaksIndex)):
|
|
773
|
-
x = wavel[peaksIndex[i]]
|
|
774
|
-
y = peaksH[i]
|
|
775
|
-
if ylog:
|
|
776
|
-
# In log scale, we use multipliers to keep the same visual distance
|
|
777
|
-
# 1.1 means "10% above the peak"
|
|
778
|
-
# Adjust these factors based on your preference
|
|
779
|
-
y_s = y * 1.1
|
|
780
|
-
y_h = y * 1.3
|
|
781
|
-
y_a = y * 1.5
|
|
782
|
-
self.graph.vlines(x, y_s, y_h, colors=color, linestyles='solid')
|
|
783
|
-
self.graph.annotate(f"{x:.1f}",xy=(x,y),xytext=(x,y_a),rotation=90,size=self.fontsize_peaks,ha='center',va='bottom', color=color)
|
|
784
|
-
else:
|
|
785
|
-
# Classic linear offsets
|
|
786
|
-
self.graph.vlines(x, y+s, y+s+h, colors=color, linestyles='solid')
|
|
787
|
-
self.graph.annotate(f"{x:.1f}",xy=(x,y),xytext=(x,y+s+h+a),rotation=90,size=self.fontsize_peaks,ha='center',va='bottom',color=color)
|
|
788
|
-
return
|
|
789
|
-
|
|
790
|
-
def _setup_axes(self, lambdamin, lambdamax, ymax, ylabel="Absorbance"):
|
|
791
|
-
self.graph.set_xlabel('wavelength / nm', size=self.fontSize_axisLabels, fontweight='bold', color='#2f6b91')
|
|
792
|
-
self.graph.set_ylabel(ylabel, size=self.fontSize_axisLabels, fontweight='bold', color='#2f6b91')
|
|
793
|
-
self.graph.set_xlim(lambdamin, lambdamax)
|
|
794
|
-
self.graph.set_ylim(0, ymax)
|
|
795
|
-
self.graph.tick_params(axis='both', labelsize=self.fontSize_axisText,labelcolor='black')
|
|
796
|
-
for tick in self.graph.xaxis.get_majorticklabels(): tick.set_fontweight('bold') #it is both powerful
|
|
797
|
-
# (you can specify the type of a specific tick) and annoying
|
|
798
|
-
for tick in self.graph.yaxis.get_majorticklabels(): tick.set_fontweight('bold')
|
|
799
|
-
|
|
800
|
-
def plotTDDFTSpectrum(self,wavel,sumInt,wavelTAB,feTAB,tP,ylog,labelSpectrum,colorS='#0000ff',colorT='#0000cf'):
|
|
801
|
-
|
|
802
|
-
'''
|
|
803
|
-
Called by plotEps_lambda_TDDFT. Plots a single simulated UV-Vis spectrum, i.e. after
|
|
804
|
-
gaussian broadening, together with the TDDFT vertical transitions (i.e. plotted as lines)
|
|
805
|
-
|
|
806
|
-
input:
|
|
807
|
-
- wavel = array of gaussian-broadened wavelengths, in nm
|
|
808
|
-
- sumInt = corresponding molar absorptiopn coefficients, in L. mol-1 cm-1
|
|
809
|
-
- wavelTAB = wavelength of TDDFT, e.g. discretized, transitions
|
|
810
|
-
- ylog = log plot of epsilon
|
|
811
|
-
- tP: threshold for finding the peaks
|
|
812
|
-
- feTAB = TDDFT oscillator strength for each transition of wavelTAB
|
|
813
|
-
- labelSpectrum = title for the spectrum
|
|
814
|
-
'''
|
|
815
|
-
|
|
816
|
-
# # --- DEBUG START ---
|
|
817
|
-
# if ylog:
|
|
818
|
-
# print(f"\n--- DEBUG LOG MODE ---")
|
|
819
|
-
# print(f"Max sumInt (linear): {np.max(sumInt):.2f}")
|
|
820
|
-
# print(f"Max sumInt (log10): {np.log10(max(np.max(sumInt), 1e-5)):.2f}")
|
|
821
|
-
# # --- DEBUG END ---
|
|
822
|
-
if ylog:
|
|
823
|
-
# Apply safety floor to the entire array
|
|
824
|
-
self.graph.set_yscale('log')
|
|
825
|
-
ymin_val = 1.0 # Epsilon = 1
|
|
826
|
-
else:
|
|
827
|
-
self.graph.set_yscale('linear')
|
|
828
|
-
ymin_val = 0
|
|
829
|
-
|
|
830
|
-
# vertical lines
|
|
831
|
-
for i in range(len(wavelTAB)):
|
|
832
|
-
val_eps = self._calc_epsiG(wavelTAB[i],wavelTAB[i],feTAB[i])
|
|
833
|
-
self.graph.vlines(x=wavelTAB[i], ymin=ymin_val, ymax=max(val_eps, ymin_val), colors=colorT)
|
|
834
|
-
|
|
835
|
-
self.graph.plot(wavel,sumInt,linewidth=3,linestyle='-',color=colorS,label=labelSpectrum)
|
|
836
|
-
|
|
837
|
-
self.graph.legend(fontsize=self.fontSize_legends)
|
|
838
|
-
if ylog:
|
|
839
|
-
# Use log-transformed data and log-transformed threshold
|
|
840
|
-
# Clipping tP to 1e-5 ensures we don't take log of 0 or negative
|
|
841
|
-
tPlog = np.log10(max(tP, 1e-5))
|
|
842
|
-
# prom=0.05 allows detection of peaks that are close in log-magnitude
|
|
843
|
-
peaks, peaksH_log = self._FindPeaks(np.log10(np.clip(sumInt, 1e-5, None)), tPlog, prom=0.05)
|
|
844
|
-
peaksH = 10**peaksH_log
|
|
845
|
-
# shoulders, shouldersH_log = self._FindShoulders(np.log10(np.clip(sumInt, 1e-5, None)), tPlog)
|
|
846
|
-
# all_idx = np.concatenate((peaks, shoulders))
|
|
847
|
-
# allH_log = np.concatenate((peaksH_log, shouldersH_log))
|
|
848
|
-
# allH = 10**allH_log
|
|
849
|
-
else:
|
|
850
|
-
peaks, peaksH = self._FindPeaks(sumInt,tP)
|
|
851
|
-
# shoulders, shouldersH = self._FindShoulders(wavel, sumInt, tP)
|
|
852
|
-
# all_idx = np.concatenate((peaks, shoulders))
|
|
853
|
-
# allH = np.concatenate((peaksH, shouldersH))
|
|
854
|
-
self._pickPeak(wavel,peaks,peaksH,colorS,500,500,200,ylog)
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
def plotEps_lambda_TDDFT(self,datFile,lambdamin=200,lambdamax=800,\
|
|
858
|
-
epsMax=None, titles=None, tP = 10, \
|
|
859
|
-
ylog=False,\
|
|
860
|
-
filename=None):
|
|
861
|
-
'''
|
|
862
|
-
Plots a TDDFT VUV simulated spectrum (vertical transitions and transitions summed with gaussian functions)
|
|
863
|
-
between lambdamin and lambdamax (sum of states done in the range [lambdamin-50, lambdamlax+50] nm)
|
|
864
|
-
input:
|
|
865
|
-
- datFile: list of pathway/names to "XXX_ExcStab.dat" files generated by 'GParser Gaussian.log -S'
|
|
866
|
-
- lambdamin, lambdamax: plot range
|
|
867
|
-
- epsMax: y axis graph limit
|
|
868
|
-
- titles: list of titles (1 per spectrum plot)
|
|
869
|
-
- tP: threshold for finding the peaks (default = 10 L. mol-1 cm-1)
|
|
870
|
-
- ylog: y logarithmic axis (default: False).
|
|
871
|
-
- save: saves in a png file (300 dpi) if True (default = False)
|
|
872
|
-
- filename: saves figure in a 300 dpi png file if not None (default), with filename=full pathway
|
|
873
|
-
'''
|
|
874
|
-
if self.fig is not None:
|
|
875
|
-
graph = self.graph
|
|
876
|
-
fig = self.fig
|
|
877
|
-
lambdamin = self.lambdamin
|
|
878
|
-
lambdamax = self.lambdamax
|
|
879
|
-
epsMax = self.epsMax
|
|
880
|
-
else:
|
|
881
|
-
fig, graph = self._initializePlot()
|
|
882
|
-
|
|
883
|
-
graph.set_prop_cycle(None)
|
|
884
|
-
|
|
885
|
-
if self.fig is None:
|
|
886
|
-
self.fig = fig
|
|
887
|
-
self.graph = graph
|
|
888
|
-
self.lambdamin = lambdamin
|
|
889
|
-
self.lambdamax = lambdamax
|
|
890
|
-
self.epsMax = epsMax
|
|
891
|
-
|
|
892
|
-
graph.set_xlabel('wavelength / nm',size=self.fontSize_axisLabels,fontweight='bold',color='#2f6b91')
|
|
893
|
-
|
|
894
|
-
graph.set_xlim(lambdamin,lambdamax)
|
|
895
|
-
|
|
896
|
-
import matplotlib.ticker as ticker
|
|
897
|
-
graph.xaxis.set_major_locator(ticker.MultipleLocator(50)) # sets a tick for every integer multiple of the base (here 250) within the view interval
|
|
898
|
-
|
|
899
|
-
istate,state,wavel,fe,SSq = np.genfromtxt(datFile,skip_header=1,dtype="<U20,<U20,float,float,<U20",unpack=True)
|
|
900
|
-
wavel = np.array(wavel)
|
|
901
|
-
fe = np.array(fe)
|
|
902
|
-
if wavel.size == 1:
|
|
903
|
-
wavel = np.array([wavel])
|
|
904
|
-
fe = np.array([fe])
|
|
905
|
-
wvl = np.arange(lambdamin-50,lambdamax+50,1)
|
|
906
|
-
sumInt = self._sumStatesWithGf(wvl,wavel,fe)
|
|
907
|
-
self.plotTDDFTSpectrum(wvl,sumInt,wavel,fe,tP,ylog,titles,self.colorS,self.colorVT)
|
|
908
|
-
if ylog:
|
|
909
|
-
graph.set_ylabel('log(molar absorption coefficient / L mol$^{-1}$ cm$^{-1})$',size=self.fontSize_axisLabels,fontweight='bold',color='#2f6b91')
|
|
910
|
-
graph.set_ylim(1, epsMax * 5 if epsMax else None)
|
|
911
|
-
else:
|
|
912
|
-
graph.set_yscale('linear')
|
|
913
|
-
graph.set_ylabel('molar absorption coefficient / L mol$^{-1}$ cm$^{-1}$',size=self.fontSize_axisLabels,fontweight='bold',color='#2f6b91')
|
|
914
|
-
graph.set_ylim(0, epsMax if epsMax else np.max(sumInt)*1.18)
|
|
915
|
-
if filename is not None: self.fig.savefig(filename, dpi=300, bbox_inches='tight')
|
|
916
|
-
plt.show()
|
|
917
|
-
|
|
918
|
-
peaksI, peaksH = self._FindPeaks(sumInt,tP)
|
|
919
|
-
print(f"{bg.LIGHTREDB}{titles}{bg.OFF}")
|
|
920
|
-
for i in range(len(peaksI)):
|
|
921
|
-
print(f"peak {i:3}. {wvl[peaksI[i]]:4} nm. epsilon_max = {peaksH[i]:.1f} L mol-1 cm-1")
|
|
922
|
-
if ylog:
|
|
923
|
-
print()
|
|
924
|
-
# prom=0.05 allows detection of peaks that are close in log-magnitude
|
|
925
|
-
peaksI, peaksH = self._FindPeaks(np.log10(np.clip(sumInt, 1e-5, None)), np.log10(max(tP, 1e-5)), prom=0.05)
|
|
926
|
-
for i in range(len(peaksI)):
|
|
927
|
-
print(f"peak {i:3}. {wvl[peaksI[i]]:4} nm. log10(epsilon_max) = {peaksH[i]:.1f}")
|
|
928
|
-
|
|
929
|
-
def plotAbs_lambda_TDDFT(self, datFiles=None, C0=1e-5, lambdamin=200, lambdamax=800, Amax=2.0,\
|
|
930
|
-
titles=None, linestyles=[], annotateP=[], tP = 0.1,\
|
|
931
|
-
resetColors=False,\
|
|
932
|
-
filename=None):
|
|
933
|
-
'''
|
|
934
|
-
Plots a simulated TDDFT VUV absorbance spectrum (transitions summed with gaussian functions)
|
|
935
|
-
between lambdamin and lambdamax (sum of states done in the range [lambdamin-50, lambdamlax+50] nm)
|
|
936
|
-
input:
|
|
937
|
-
- datFiles: list of pathway/name to files generated by 'GParser Gaussian.log -S'
|
|
938
|
-
- C0: list of concentrations needed to calculate A = epsilon x l x c (in mol.L-1)
|
|
939
|
-
- lambdamin, lambdamax: plot range (x axis)
|
|
940
|
-
- Amax: y axis graph limit
|
|
941
|
-
- titles: list of titles (1 per spectrum plot)
|
|
942
|
-
- linestyles: list of line styles(default = "-", i.e. a continuous line)
|
|
943
|
-
- annotateP: list of Boolean (annotate lambda max True or False. Default = True)
|
|
944
|
-
- tP: threshold for finding the peaks (default = 0.1)
|
|
945
|
-
- resetColors (bool): If True, resets the matplotlib color cycle
|
|
946
|
-
to the first color. This allows different series
|
|
947
|
-
(e.g., gas phase vs. solvent) to share the same
|
|
948
|
-
color coding for each molecule across multiple calls. Default: False
|
|
949
|
-
- save: saves in a png file (300 dpi) if True (default = False)
|
|
950
|
-
- filename: saves figure in a 300 dpi png file if not None (default), with filename=full pathway
|
|
951
|
-
'''
|
|
952
|
-
|
|
953
|
-
if self.fig is None:
|
|
954
|
-
fig, graph = self._initializePlot()
|
|
955
|
-
self.fig = fig
|
|
956
|
-
self.graph = graph
|
|
957
|
-
self.lambdamin = lambdamin
|
|
958
|
-
self.lambdamax = lambdamax
|
|
959
|
-
self.Amax = Amax
|
|
960
|
-
else:
|
|
961
|
-
graph = self.graph
|
|
962
|
-
fig = self.fig
|
|
963
|
-
lambdamin = self.lambdamin
|
|
964
|
-
lambdamax = self.lambdamax
|
|
965
|
-
Amax = self.Amax
|
|
966
|
-
if resetColors: graph.set_prop_cycle(None)
|
|
967
|
-
|
|
968
|
-
if linestyles == []: linestyles = len(datFiles)*['-']
|
|
969
|
-
if annotateP == []: annotateP = len(datFiles)*[True]
|
|
970
|
-
|
|
971
|
-
self._setup_axes(lambdamin, lambdamax, self.Amax, ylabel="Absorbance")
|
|
972
|
-
|
|
973
|
-
wvl = np.arange(lambdamin-50,lambdamax+50,1)
|
|
974
|
-
for f in range(len(datFiles)):
|
|
975
|
-
istate,state,wavel,fe,SSq = np.genfromtxt(datFiles[f],skip_header=1,dtype="<U20,<U20,float,float,<U20",unpack=True)
|
|
976
|
-
sumInt = self._sumStatesWithGf(wvl,wavel,fe)
|
|
977
|
-
Abs = self._Absorbance(sumInt,1,C0[f])
|
|
978
|
-
plot=self.graph.plot(wvl,Abs,linewidth=3,linestyle=linestyles[f],label=f"{titles[f]}. TDDFT ($C_0$={C0[f]} mol/L)")
|
|
979
|
-
peaksI, peaksH = self._FindPeaks(Abs,tP,0.01)
|
|
980
|
-
if (annotateP[f]): self._pickPeak(wvl,peaksI,peaksH,plot[0].get_color(),0.01,0.04,0.02)
|
|
981
|
-
print(f"{bg.LIGHTREDB}TDDFT. {titles[f]}{bg.OFF}")
|
|
982
|
-
for i in range(len(peaksI)):
|
|
983
|
-
print(f"peak {i:3}. {wvl[peaksI[i]]:4} nm. A = {peaksH[i]:.2f}")
|
|
984
|
-
|
|
985
|
-
self.graph.legend(fontsize=self.fontSize_legends)
|
|
986
|
-
|
|
987
|
-
if filename is not None: self.fig.savefig(filename, dpi=300, bbox_inches='tight')
|
|
988
|
-
|
|
989
|
-
return
|
|
990
|
-
|
|
991
|
-
def plotAbs_lambda_exp(self, csvFiles, C0, lambdamin=200, lambdamax=800,\
|
|
992
|
-
Amax=2.0, titles=None, linestyles=[], annotateP=[], tP = 0.1,\
|
|
993
|
-
filename=None):
|
|
994
|
-
'''
|
|
995
|
-
Plots an experimental VUV absorbance spectrum read from a csv file between lambdamin and lambdamax
|
|
996
|
-
input:
|
|
997
|
-
- superpose: False = plots a new graph, otherwise the plot is superposed to a previously created one
|
|
998
|
-
(probably with plotAbs_lambda_TDDFT())
|
|
999
|
-
- csvfiles: list of pathway/name to experimental csvFiles (see examples for the format)
|
|
1000
|
-
- C0: list of experimental concentrations, i.e. for each sample
|
|
1001
|
-
- lambdamin, lambdamax: plot range (x axis)
|
|
1002
|
-
- Amax: graph limit (y axis)
|
|
1003
|
-
- titles: list of titles (1 per spectrum plot)
|
|
1004
|
-
- linestyles: list of line styles(default = "--", i.e. a dashed line)
|
|
1005
|
-
- annotateP: list of Boolean (annotate lambda max True or False. Default = True)
|
|
1006
|
-
- tP: threshold for finding the peaks (default = 0.1)
|
|
1007
|
-
- save: saves in a png file (300 dpi) if True (default = False)
|
|
1008
|
-
- filename: saves figure in a 300 dpi png file if not None (default), with filename=full pathway
|
|
1009
|
-
'''
|
|
1010
|
-
if linestyles == []: linestyles = len(csvFiles)*['--']
|
|
1011
|
-
if annotateP == []: annotateP = len(csvFiles)*[True]
|
|
1012
|
-
|
|
1013
|
-
if self.fig is not None:
|
|
1014
|
-
graph = self.graph
|
|
1015
|
-
fig = self.fig
|
|
1016
|
-
lambdamin = self.lambdamin
|
|
1017
|
-
lambdamax = self.lambdamax
|
|
1018
|
-
Amax = self.Amax
|
|
1019
|
-
else:
|
|
1020
|
-
fig, graph = self._initializePlot()
|
|
1021
|
-
|
|
1022
|
-
graph.set_prop_cycle(None)
|
|
1023
|
-
|
|
1024
|
-
if self.fig is None:
|
|
1025
|
-
self.graph = graph
|
|
1026
|
-
self.fig = fig
|
|
1027
|
-
self.lambdamin = lambdamin
|
|
1028
|
-
self.lambdamax = lambdamax
|
|
1029
|
-
self.Amax = Amax
|
|
1030
|
-
|
|
1031
|
-
self._setup_axes(lambdamin, lambdamax, self.Amax, ylabel="Absorbance")
|
|
1032
|
-
|
|
1033
|
-
for f in range(len(csvFiles)):
|
|
1034
|
-
wavel,Abs = np.genfromtxt(csvFiles[f],skip_header=1,unpack=True,delimiter=";")
|
|
1035
|
-
wavel *= 1e9
|
|
1036
|
-
plot=graph.plot(wavel,Abs,linewidth=3,linestyle=linestyles[f],label=f"{titles[f]}. exp ($C_0$={C0[f]} mol/L)")
|
|
1037
|
-
peaksI, peaksH = self._FindPeaks(Abs,tP,0.01)
|
|
1038
|
-
if (annotateP[f]): self._pickPeak(wavel,peaksI,peaksH,plot[0].get_color(),0.01,0.04,0.02)
|
|
1039
|
-
print(f"{bg.LIGHTREDB}exp. {titles[f]}{bg.OFF}")
|
|
1040
|
-
for i in range(len(peaksI)):
|
|
1041
|
-
print(f"peak {i:3}. {wavel[peaksI[i]]:4} nm. A = {peaksH[i]:.2f}")
|
|
1042
|
-
|
|
1043
|
-
graph.legend(fontsize=self.fontSize_legends)
|
|
1044
|
-
|
|
1045
|
-
if filename is not None: self.fig.savefig(filename, dpi=300, bbox_inches='tight')
|
|
1046
|
-
|
|
1047
|
-
return
|
|
1048
|
-
|
|
@@ -8,11 +8,9 @@ def PrintLatexStyleSymPyEquation(spe):
|
|
|
8
8
|
"""
|
|
9
9
|
Function that displays a SymPy expression (spe) in a jupyter notebbok after its conversion into a LaTeX / Math output
|
|
10
10
|
|
|
11
|
-
Input:
|
|
12
|
-
spe: SymPy expression
|
|
11
|
+
Input: spe= SymPy expression
|
|
13
12
|
|
|
14
|
-
Output:
|
|
15
|
-
Pretty printing of spe
|
|
13
|
+
Output: Pretty printing of spe
|
|
16
14
|
|
|
17
15
|
"""
|
|
18
16
|
from IPython.display import display,Math
|
|
@@ -23,12 +21,14 @@ def PrintLatexStyleSymPyEquation(spe):
|
|
|
23
21
|
def e2Lists(eigenvectors, sort=False):
|
|
24
22
|
'''
|
|
25
23
|
returns two separate lists from the list of tuples returned by the eigenvects() function of SymPy
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
|
|
25
|
+
input:
|
|
26
|
+
- the list of tuples returned by eigenvects
|
|
27
|
+
- sort (default: False): returns sorted eigenvalues and corresponding eigenvectors if True
|
|
28
|
+
|
|
29
29
|
output
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
- list of eigenvalues, sorted or not
|
|
31
|
+
- list of corresponding eigenvectors
|
|
32
32
|
'''
|
|
33
33
|
import numpy as np
|
|
34
34
|
eps = list()
|
pyphyschemtools/tools4AS.py
CHANGED
|
@@ -30,22 +30,24 @@ import seaborn as sns
|
|
|
30
30
|
|
|
31
31
|
def verifNotes(dfCC,labelNoteCC,nomCC,NI,absents='aabs'):
|
|
32
32
|
"""
|
|
33
|
-
|
|
33
|
+
Args:
|
|
34
34
|
- dfCC = dataframe dont 1 colonne contient les notes de CC
|
|
35
35
|
- labelNoteCC = label de la colonne qui contient les notes
|
|
36
36
|
- nomCC = label de l'épreuve de CC (ex CC1), utilisé pour l'affichage
|
|
37
37
|
- NI = nombre d'inscrits dans le module
|
|
38
|
-
- absents
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
- absents:
|
|
39
|
+
* 'aabs' : analyser s'il y a des étudiants qui n'ont pas été pointés au CC (défaut)
|
|
40
|
+
* 'noabs' : ne pas analyser s'il y a des étudiants qui n'ont pas été pointés au CC
|
|
41
|
+
(ça n'a plus de sens une fois les fichiers concaténés)
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
Returns:
|
|
43
44
|
- la moyenne et la déviation standard de liste de notes contenues dans le dataframe dfCC
|
|
44
45
|
- le nombre d'étudiants qui n'ont pas composé au CC
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
Note:
|
|
48
|
+
Affiche le nombre d'étudiants avec le label 'ABS' et signale les
|
|
49
|
+
étudiants sans note ni label, ce qui nécessite une vérification du PV.
|
|
50
|
+
|
|
49
51
|
"""
|
|
50
52
|
print()
|
|
51
53
|
#pd.set_option("display.max_rows", len(dfCC))
|
|
@@ -81,9 +83,11 @@ def RenameDfHeader(dfCC,dfCCname,labelNoteCC,nomCC):
|
|
|
81
83
|
- dfCCname = nom (string) du dataframe. Il est recommandé d'utiliser f'{dfCC=}'.split('=')[0]
|
|
82
84
|
- labelNoteCC = label de la colonne qui contient les notes
|
|
83
85
|
- nomCC = label de l'épreuve de CC (ex CC1), utilisé pour l'affichage
|
|
86
|
+
|
|
84
87
|
sortie : aucune
|
|
85
88
|
|
|
86
89
|
la fonction change le nom 'labelNoteCC' en 'nomCC'
|
|
90
|
+
|
|
87
91
|
"""
|
|
88
92
|
print(f"{hl.BOLD}{fg.BLUE}Normalisation du nom des colonnes de notes{fg.OFF}")
|
|
89
93
|
print(f"{hl.BOLD}Dataframe = {dfCCname}.{fg.OFF} {labelNoteCC} --> {nomCC}")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyphyschemtools
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: A comprehensive Python toolbox for physical chemistry and cheminformatics
|
|
5
5
|
Author-email: "Romuald POTEAU, LPCNO" <romuald.poteau@utoulouse.fr>
|
|
6
6
|
Project-URL: Homepage, https://github.com/rpoteau/pyphyschemtools
|
|
@@ -29,7 +29,7 @@ Requires-Dist: numpydoc; extra == "docs"
|
|
|
29
29
|
Dynamic: license-file
|
|
30
30
|
|
|
31
31
|
<div style="text-align:center">
|
|
32
|
-
<img src="https://raw.githubusercontent.com/rpoteau/pyphyschemtools/main/pyphyschemtools/
|
|
32
|
+
<img src="https://raw.githubusercontent.com/rpoteau/pyphyschemtools/main/pyphyschemtools/icons_logos_banner/tools4pyPC_banner.png" alt="t4pyPCbanner" width="800"/>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
35
35
|
# pyPhysChemTools
|
|
@@ -1,22 +1,31 @@
|
|
|
1
|
-
pyphyschemtools
|
|
2
|
-
pyphyschemtools/
|
|
3
|
-
pyphyschemtools/
|
|
4
|
-
pyphyschemtools/
|
|
5
|
-
pyphyschemtools/
|
|
1
|
+
pyphyschemtools/.__init__.py.swp,sha256=JxmB0a9RQHIw7mLGqOKJivHfhEca0dQRe3uVOBKNh9E,12288
|
|
2
|
+
pyphyschemtools/Chem3D.py,sha256=LGMZYXF3iKaXERZGFCaqql3mQMN3di47TWv39FWSj3U,32719
|
|
3
|
+
pyphyschemtools/ML.py,sha256=kR_5vm5TOOjVef8uXCW57y7685ts6K6OkRMBYKP_cYw,1599
|
|
4
|
+
pyphyschemtools/PeriodicTable.py,sha256=LfLSFOzRkirREQlwfeSR3TyvgHyjGiltIZXNmvBkbhQ,13526
|
|
5
|
+
pyphyschemtools/__init__.py,sha256=eXy78i-LH0iSpim6IJfnmvAEW_pY8RlQsKT5lhpAErU,1442
|
|
6
|
+
pyphyschemtools/aithermo.py,sha256=kF8wtuYIJzkUKM2AGubmn9haAJKz-XaBskZ7HjivJeY,14984
|
|
6
7
|
pyphyschemtools/cheminformatics.py,sha256=Qps_JSYWOzZQcXwKElI1iWGjWAPDgwmtDKuJwONsKmI,8977
|
|
7
|
-
pyphyschemtools/core.py,sha256=
|
|
8
|
+
pyphyschemtools/core.py,sha256=5fRu83b125w2p_m2H521fLjktyswZHJXNKww1wfBwbU,4847
|
|
8
9
|
pyphyschemtools/kinetics.py,sha256=3YyzzQ7FKZ7wNALRDsLNLhpZpDp38LHWOUfMojsh8hE,7696
|
|
9
|
-
pyphyschemtools/spectra.py,sha256=
|
|
10
|
-
pyphyschemtools/survey.py,sha256=
|
|
11
|
-
pyphyschemtools/sympyUtilities.py,sha256=
|
|
12
|
-
pyphyschemtools/tools4AS.py,sha256=
|
|
10
|
+
pyphyschemtools/spectra.py,sha256=eCN9X6pK5k4KMcfWUskedWYwtxbrmJH_BvFXU1GZfVo,21702
|
|
11
|
+
pyphyschemtools/survey.py,sha256=YjZhhb8GFVNXoXSCxgGdZFqmCtNCx7O_uiFVCcGBYYo,24268
|
|
12
|
+
pyphyschemtools/sympyUtilities.py,sha256=LgLloh9dD9Mkff2WNoSnrJa3hxK0axOnK-4GS9wPtT0,1545
|
|
13
|
+
pyphyschemtools/tools4AS.py,sha256=BVfxf6bHnCciBMdQBSJ76Ja_aA-I_iOqQHZuVb-DsdY,44783
|
|
13
14
|
pyphyschemtools/visualID.py,sha256=JlAd5nnZIliHOiKvkToArYhkbty-OntuFGf2CdPbgo8,3061
|
|
14
15
|
pyphyschemtools/visualID_Eng.py,sha256=o-EdCOduo_qruRrr5kkplixaT1t79f3I3M1Ya5TOc_Q,5244
|
|
15
|
-
pyphyschemtools/
|
|
16
|
-
pyphyschemtools/
|
|
17
|
-
pyphyschemtools/
|
|
18
|
-
pyphyschemtools/
|
|
19
|
-
pyphyschemtools/
|
|
16
|
+
pyphyschemtools/.ipynb_checkpoints/Chem3D-checkpoint.py,sha256=LGMZYXF3iKaXERZGFCaqql3mQMN3di47TWv39FWSj3U,32719
|
|
17
|
+
pyphyschemtools/.ipynb_checkpoints/PeriodicTable-checkpoint.py,sha256=LfLSFOzRkirREQlwfeSR3TyvgHyjGiltIZXNmvBkbhQ,13526
|
|
18
|
+
pyphyschemtools/.ipynb_checkpoints/aithermo-checkpoint.py,sha256=kF8wtuYIJzkUKM2AGubmn9haAJKz-XaBskZ7HjivJeY,14984
|
|
19
|
+
pyphyschemtools/.ipynb_checkpoints/core-checkpoint.py,sha256=5fRu83b125w2p_m2H521fLjktyswZHJXNKww1wfBwbU,4847
|
|
20
|
+
pyphyschemtools/.ipynb_checkpoints/spectra-checkpoint.py,sha256=eCN9X6pK5k4KMcfWUskedWYwtxbrmJH_BvFXU1GZfVo,21702
|
|
21
|
+
pyphyschemtools/.ipynb_checkpoints/survey-checkpoint.py,sha256=Rcw0xb0_nwsxETleB1C2xjKmZfrUw4PXDm48CMSptHU,45816
|
|
22
|
+
pyphyschemtools/.ipynb_checkpoints/sympyUtilities-checkpoint.py,sha256=LgLloh9dD9Mkff2WNoSnrJa3hxK0axOnK-4GS9wPtT0,1545
|
|
23
|
+
pyphyschemtools/.ipynb_checkpoints/tools4AS-checkpoint.py,sha256=BVfxf6bHnCciBMdQBSJ76Ja_aA-I_iOqQHZuVb-DsdY,44783
|
|
24
|
+
pyphyschemtools/icons_logos_banner/Logo_pyPhysChem_border.svg,sha256=w6AhEF3Ym5Xe6AyUJ0WZ8rTzYXCFCSQLCAftrmPaG7w,55288
|
|
25
|
+
pyphyschemtools/icons_logos_banner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
+
pyphyschemtools/icons_logos_banner/logo.png,sha256=qnxdLQGvv1TNcz_n4EseQhzZgIX6O710tqm418_EIRY,388311
|
|
27
|
+
pyphyschemtools/icons_logos_banner/tools4pyPC_banner.png,sha256=z7o_kBK0sIBsXHEJrT2GyLHu-0T0T3S8YkWcpxR2joA,89058
|
|
28
|
+
pyphyschemtools/icons_logos_banner/tools4pyPC_banner.svg,sha256=JQhtJmTXkatvHwGtSc0gHBTZB_E0eh_nLB9kX7sxt7k,99752
|
|
20
29
|
pyphyschemtools/resources/css/BrainHalfHalf-120x139.base64,sha256=rn-r0NKiX92EEEOlME-nUw_fC8B6mrEThX7v9L1y4Eg,25092
|
|
21
30
|
pyphyschemtools/resources/css/BrainHalfHalf-120x139.png,sha256=tBhhTXidkqjvmavprPAl3BZlsqswu7DbP_rAz-tyS_Q,18818
|
|
22
31
|
pyphyschemtools/resources/css/BrainHalfHalf.base64,sha256=0VLlFvSdEaVfHJR-RDNu27V0PzBN0HSfsXxGU0mRFXw,633735
|
|
@@ -73,8 +82,8 @@ pyphyschemtools/resources/svg/pyPhysChemBanner.png,sha256=sK5NwjbEYJvMAAzPBCqwvr
|
|
|
73
82
|
pyphyschemtools/resources/svg/pyPhysChemBanner.svg,sha256=39LrLnFn7R681Hh3YXB3K17Sp0Xp3ynDOGUbXuORQ3s,4388883
|
|
74
83
|
pyphyschemtools/resources/svg/qrcode-pyPhysChem.png,sha256=rP7X-9eHL7HYj4ffmwBMLfQTaRIOyzShVfavRXiomtw,71070
|
|
75
84
|
pyphyschemtools/resources/svg/repository-open-graph-template.png,sha256=UlnW5BMkLGOv6IAnEi7teDYS_5qeSLmpxRMT9r9m-5Q,51470
|
|
76
|
-
pyphyschemtools-0.1.
|
|
77
|
-
pyphyschemtools-0.1.
|
|
78
|
-
pyphyschemtools-0.1.
|
|
79
|
-
pyphyschemtools-0.1.
|
|
80
|
-
pyphyschemtools-0.1.
|
|
85
|
+
pyphyschemtools-0.1.1.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
86
|
+
pyphyschemtools-0.1.1.dist-info/METADATA,sha256=uF9M1xAqA8jqN1fM-YJloiB7vLRrCtQamavjAHxchHE,1352
|
|
87
|
+
pyphyschemtools-0.1.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
88
|
+
pyphyschemtools-0.1.1.dist-info/top_level.txt,sha256=N92w2qk4LQ42OSdzK1R2h_x1CyUFaFBOrOML2RnmFgE,16
|
|
89
|
+
pyphyschemtools-0.1.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|