yu-mcal 0.1.0__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.
- mcal/__init__.py +1 -0
- mcal/calculations/__init__.py +0 -0
- mcal/calculations/hopping_mobility_model.py +391 -0
- mcal/calculations/rcal.py +408 -0
- mcal/calculations/tcal.py +1123 -0
- mcal/constants/element_properties.csv +121 -0
- mcal/mcal.py +838 -0
- mcal/utils/__init__.py +0 -0
- mcal/utils/cif_reader.py +645 -0
- mcal/utils/gaus_log_reader.py +91 -0
- mcal/utils/gjf_maker.py +267 -0
- yu_mcal-0.1.0.dist-info/METADATA +257 -0
- yu_mcal-0.1.0.dist-info/RECORD +16 -0
- yu_mcal-0.1.0.dist-info/WHEEL +4 -0
- yu_mcal-0.1.0.dist-info/entry_points.txt +2 -0
- yu_mcal-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""Gaussian log file reader (2025/06/21)"""
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def check_normal_termination(log_file: str) -> bool:
|
|
7
|
+
"""Check if the calculation terminated normally.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
log_file : str
|
|
12
|
+
Path to the log file
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
bool
|
|
17
|
+
True if the calculation terminated normally, False otherwise
|
|
18
|
+
"""
|
|
19
|
+
if not Path(log_file).exists():
|
|
20
|
+
return False
|
|
21
|
+
|
|
22
|
+
with FileReader(log_file) as f:
|
|
23
|
+
line = f.reversed_readline()
|
|
24
|
+
if 'Normal termination' in line:
|
|
25
|
+
return True
|
|
26
|
+
else:
|
|
27
|
+
return False
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FileReader:
|
|
31
|
+
"""File reader that reads line by line from the end.
|
|
32
|
+
|
|
33
|
+
Examples
|
|
34
|
+
--------
|
|
35
|
+
>>> with FileReader('sample.txt') as f:
|
|
36
|
+
... while True:
|
|
37
|
+
... line = f.reversed_readline()
|
|
38
|
+
... if not line:
|
|
39
|
+
... break
|
|
40
|
+
... print(line)
|
|
41
|
+
"""
|
|
42
|
+
def __init__(self, file_path, buffer_size=8192):
|
|
43
|
+
self.buffer_size = buffer_size
|
|
44
|
+
self.file = open(file_path, 'rb')
|
|
45
|
+
# ファイルポインタをファイルの末尾に移動
|
|
46
|
+
self.file.seek(0, os.SEEK_END)
|
|
47
|
+
self.file_size = self.file.tell()
|
|
48
|
+
# 最後のブロックの終了位置をファイルサイズに設定
|
|
49
|
+
self.reversed_block_end = self.file_size
|
|
50
|
+
# 最後のブロックの開始位置を計算(ファイル末尾からバッファサイズ分前、またはファイル先頭)
|
|
51
|
+
self.reversed_block_start = max(0, self.reversed_block_end - self.buffer_size)
|
|
52
|
+
self.lines = []
|
|
53
|
+
|
|
54
|
+
def __enter__(self):
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
58
|
+
self.close()
|
|
59
|
+
|
|
60
|
+
def close(self):
|
|
61
|
+
self.file.close()
|
|
62
|
+
|
|
63
|
+
def reversed_readline(self):
|
|
64
|
+
if not self.lines and self.reversed_block_end - self.reversed_block_start != 0:
|
|
65
|
+
# ファイルポインタを現在のブロックの開始位置に設定
|
|
66
|
+
self.file.seek(self.reversed_block_start)
|
|
67
|
+
|
|
68
|
+
block = self.file.read(self.reversed_block_end - self.reversed_block_start)
|
|
69
|
+
lines = block.splitlines(keepends=True)
|
|
70
|
+
|
|
71
|
+
# 現在のブロックがファイルの最初のブロックの場合
|
|
72
|
+
if self.reversed_block_start == 0:
|
|
73
|
+
# ブロックの終了位置を開始位置に設定して次の読み取りを防ぐ
|
|
74
|
+
self.reversed_block_end = self.reversed_block_start
|
|
75
|
+
else:
|
|
76
|
+
# 次のブロックの終了位置を更新(現在のブロックの最初の行の長さを加算)
|
|
77
|
+
self.reversed_block_end = max(0, self.reversed_block_start + len(lines[0]))
|
|
78
|
+
|
|
79
|
+
self.reversed_block_start = max(0, self.reversed_block_end - self.buffer_size)
|
|
80
|
+
|
|
81
|
+
# 末尾のブロックの場合、全行を読み取る
|
|
82
|
+
if self.reversed_block_end == 0:
|
|
83
|
+
self.lines = lines
|
|
84
|
+
else:
|
|
85
|
+
self.lines = lines[1:]
|
|
86
|
+
|
|
87
|
+
return self.lines.pop().decode('utf-8')
|
|
88
|
+
elif self.lines:
|
|
89
|
+
return self.lines.pop().decode('utf-8')
|
|
90
|
+
else:
|
|
91
|
+
return None
|
mcal/utils/gjf_maker.py
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
""" GjfMaker beta (2025/08/18)"""
|
|
2
|
+
import os
|
|
3
|
+
import warnings
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import List, Optional, Tuple
|
|
6
|
+
|
|
7
|
+
import pandas as pd
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GjfMaker:
|
|
11
|
+
parent_dir = Path(os.path.abspath(__file__)).parent.parent
|
|
12
|
+
ELEMENT_PROP = pd.read_csv(f'{parent_dir}/constants/element_properties.csv')
|
|
13
|
+
ELEMENTS_NUM = ELEMENT_PROP[['symbol', 'number']].set_index('symbol').to_dict()['number']
|
|
14
|
+
|
|
15
|
+
def __init__(self, remove_radical_flag: bool = False) -> None:
|
|
16
|
+
"""Initialize the GjfMaker class.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
remove_radical_flag : bool
|
|
21
|
+
If True, the radical is removed, by default False.
|
|
22
|
+
Not recommended to use this flag.
|
|
23
|
+
"""
|
|
24
|
+
self.remove_radical_flag = remove_radical_flag
|
|
25
|
+
|
|
26
|
+
self._link_dict = {}
|
|
27
|
+
self._link_num = 0
|
|
28
|
+
self._cpu_num = '%NProcShared=9\n'
|
|
29
|
+
self._mem_num = '%Mem=40GB\n'
|
|
30
|
+
self._is_chk_file = False
|
|
31
|
+
self._is_rwf_file = False
|
|
32
|
+
self.is_detail = False
|
|
33
|
+
self._function = '# B3LYP/6-31G(d,p)\n'
|
|
34
|
+
self._root = []
|
|
35
|
+
self._title = '\nDefalut Title\n'
|
|
36
|
+
self._symbols = []
|
|
37
|
+
self._charge_spin = ''
|
|
38
|
+
self._coordinates = []
|
|
39
|
+
|
|
40
|
+
self._root_space = ' '
|
|
41
|
+
|
|
42
|
+
def add_link(self) -> None:
|
|
43
|
+
"""Add the link of the gjf file."""
|
|
44
|
+
self.create_chk_file()
|
|
45
|
+
self._link_dict[self._link_num] = [self._cpu_num, self._mem_num, self._function, self._root]
|
|
46
|
+
self._link_num += 1
|
|
47
|
+
self._root = ['Geom=AllCheck\n', 'Guess=Read\n']
|
|
48
|
+
|
|
49
|
+
def add_root(self, root: str) -> None:
|
|
50
|
+
"""Add the root of the gjf file."""
|
|
51
|
+
if root[0] == '#':
|
|
52
|
+
root = root[1:]
|
|
53
|
+
self._root.append(root + '\n')
|
|
54
|
+
|
|
55
|
+
def create_chk_file(self) -> None:
|
|
56
|
+
"""Create the chk file."""
|
|
57
|
+
self._is_chk_file = True
|
|
58
|
+
|
|
59
|
+
def create_rwf_file(self) -> None:
|
|
60
|
+
"""Create the rwf file."""
|
|
61
|
+
self._is_rwf_file = True
|
|
62
|
+
|
|
63
|
+
def export_gjf(
|
|
64
|
+
self,
|
|
65
|
+
file_name: str,
|
|
66
|
+
save_dir: str = '.',
|
|
67
|
+
chk_rwf_name: Optional[str] = None
|
|
68
|
+
) -> None:
|
|
69
|
+
"""Export the gjf file.
|
|
70
|
+
|
|
71
|
+
Parameters
|
|
72
|
+
----------
|
|
73
|
+
file_name : str
|
|
74
|
+
Name of the gjf file.
|
|
75
|
+
save_dir : str
|
|
76
|
+
Directory to save the gjf file.
|
|
77
|
+
chk_rwf_name : Optional[str]
|
|
78
|
+
Name of the chk or rwf file.
|
|
79
|
+
"""
|
|
80
|
+
if self.remove_radical_flag and self._check_radical():
|
|
81
|
+
print('This molecule is radical')
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
os.makedirs(save_dir, exist_ok=True)
|
|
85
|
+
|
|
86
|
+
self._link_dict[self._link_num] = [self._cpu_num, self._mem_num, self._function, self._root]
|
|
87
|
+
|
|
88
|
+
if self._is_chk_file:
|
|
89
|
+
if chk_rwf_name:
|
|
90
|
+
self._chk_file = f'%Chk={chk_rwf_name}.chk\n'
|
|
91
|
+
else:
|
|
92
|
+
self._chk_file = f'%Chk={save_dir}/{file_name}.chk\n'
|
|
93
|
+
else:
|
|
94
|
+
self._chk_file = ''
|
|
95
|
+
|
|
96
|
+
if self._is_rwf_file:
|
|
97
|
+
if chk_rwf_name:
|
|
98
|
+
self._rwf_file = f'%RWF={chk_rwf_name}.rwf\n'
|
|
99
|
+
else:
|
|
100
|
+
self._rwf_file = f'%RWF={save_dir}/{file_name}.rwf\n'
|
|
101
|
+
else:
|
|
102
|
+
self._rwf_file = ''
|
|
103
|
+
|
|
104
|
+
with open(f'{save_dir}/{file_name}.gjf', 'w') as f:
|
|
105
|
+
for i in range(self._link_num+1):
|
|
106
|
+
_cpn_num, _mem_num, _function, _root = self._link_dict[i]
|
|
107
|
+
if i > 0:
|
|
108
|
+
f.write(f'\n--Link{i}--\n')
|
|
109
|
+
f.write(_cpn_num)
|
|
110
|
+
f.write(_mem_num)
|
|
111
|
+
f.write(self._chk_file)
|
|
112
|
+
f.write(self._rwf_file)
|
|
113
|
+
f.write(_function)
|
|
114
|
+
for r in _root:
|
|
115
|
+
f.write(f'#{self._root_space}{r}')
|
|
116
|
+
|
|
117
|
+
if i == 0:
|
|
118
|
+
f.write(self._title)
|
|
119
|
+
|
|
120
|
+
if not self._charge_spin:
|
|
121
|
+
self._check_charge_spin()
|
|
122
|
+
f.write(self._charge_spin)
|
|
123
|
+
|
|
124
|
+
for sym, (x, y, z) in zip(self._symbols, self._coordinates):
|
|
125
|
+
x = f'{x:.8f}'.rjust(14, ' ')
|
|
126
|
+
y = f'{y:.8f}'.rjust(14, ' ')
|
|
127
|
+
z = f'{z:.8f}'.rjust(14, ' ')
|
|
128
|
+
f.write(f' {sym} {x} {y} {z}\n')
|
|
129
|
+
f.write('\n')
|
|
130
|
+
|
|
131
|
+
def opt(self, tight: bool = True) -> None:
|
|
132
|
+
"""Set the optimization option of the gjf file.
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
tight : bool
|
|
137
|
+
If True, the optimization is tight, by default True.
|
|
138
|
+
"""
|
|
139
|
+
opt = 'Opt'
|
|
140
|
+
if tight:
|
|
141
|
+
opt = 'Opt=Tight'
|
|
142
|
+
self.add_root(opt)
|
|
143
|
+
|
|
144
|
+
def output_detail(self) -> None:
|
|
145
|
+
"""Output the detail to log file."""
|
|
146
|
+
self.is_detail = True
|
|
147
|
+
_, function = self._function.split()
|
|
148
|
+
self._function = f'#P {function}\n'
|
|
149
|
+
self._root_space = ' '
|
|
150
|
+
|
|
151
|
+
def reset_variable(self) -> None:
|
|
152
|
+
"""Reset the variables of the gjf file."""
|
|
153
|
+
self._root = []
|
|
154
|
+
self._symbols = []
|
|
155
|
+
self._coordinates = []
|
|
156
|
+
self._link_dict = {}
|
|
157
|
+
self._link_num = 0
|
|
158
|
+
|
|
159
|
+
def set_charge_spin(self, charge: int, spin: int) -> None:
|
|
160
|
+
"""Set the charge and spin of the molecule.
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
charge : int
|
|
165
|
+
Charge of the molecule.
|
|
166
|
+
spin : int
|
|
167
|
+
Spin of the molecule.
|
|
168
|
+
"""
|
|
169
|
+
self._charge_spin = f'\n{charge} {spin}\n'
|
|
170
|
+
|
|
171
|
+
def set_coordinates(self, coordinates: List[Tuple[float, float, float]]) -> None:
|
|
172
|
+
"""Set the coordinates of the molecule.
|
|
173
|
+
|
|
174
|
+
Parameters
|
|
175
|
+
----------
|
|
176
|
+
coordinates : List[Tuple[float, float, float]]
|
|
177
|
+
Coordinates of the molecule.
|
|
178
|
+
"""
|
|
179
|
+
self._coordinates.extend(coordinates)
|
|
180
|
+
|
|
181
|
+
def set_function(self, function: str) -> None:
|
|
182
|
+
"""Set the function of the gjf file.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
function : str
|
|
187
|
+
Function of the gjf file.
|
|
188
|
+
"""
|
|
189
|
+
detail = ''
|
|
190
|
+
if self.is_detail:
|
|
191
|
+
detail = 'P'
|
|
192
|
+
|
|
193
|
+
self._function = f'#{detail} {function}\n'
|
|
194
|
+
|
|
195
|
+
def set_resource(self, cpu_num: int, mem_num: int, mem_unit: str = 'GB') -> None:
|
|
196
|
+
"""Set the number of cpu and memory.
|
|
197
|
+
|
|
198
|
+
Parameters
|
|
199
|
+
----------
|
|
200
|
+
cpu_num : int
|
|
201
|
+
Number of cpu.
|
|
202
|
+
mem_num : int
|
|
203
|
+
Number of memory.
|
|
204
|
+
mem_unit : str
|
|
205
|
+
Unit of memory, by default 'GB'.
|
|
206
|
+
"""
|
|
207
|
+
self._cpu_num = f'%NProcShared={cpu_num}\n'
|
|
208
|
+
self._mem_num = f'%Mem={mem_num}{mem_unit}\n'
|
|
209
|
+
|
|
210
|
+
def set_symbols(self, symbols: List[str]) -> None:
|
|
211
|
+
"""Set the symbols of the molecule.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
symbols : List[str]
|
|
216
|
+
Symbols of the molecule.
|
|
217
|
+
"""
|
|
218
|
+
self._symbols.extend(symbols)
|
|
219
|
+
|
|
220
|
+
def set_title(self, title: str) -> None:
|
|
221
|
+
"""Set the title of the gjf file.
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
----------
|
|
225
|
+
title : str
|
|
226
|
+
Title of the gjf file.
|
|
227
|
+
"""
|
|
228
|
+
self._title = f'\n{title}\n'
|
|
229
|
+
|
|
230
|
+
def _check_charge_spin(self) -> None:
|
|
231
|
+
"""Check the charge and spin of the molecule."""
|
|
232
|
+
elements = 0
|
|
233
|
+
|
|
234
|
+
if not self._symbols:
|
|
235
|
+
self._charge_spin = ''
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
for symbol in self._symbols:
|
|
239
|
+
elements += self.ELEMENTS_NUM[symbol]
|
|
240
|
+
|
|
241
|
+
if elements % 2 == 0:
|
|
242
|
+
self._charge_spin = '\n0 1\n'
|
|
243
|
+
else:
|
|
244
|
+
self._charge_spin = '\n0 2\n'
|
|
245
|
+
|
|
246
|
+
def _check_radical(self) -> bool:
|
|
247
|
+
"""Check if the molecule is radical.
|
|
248
|
+
|
|
249
|
+
Returns
|
|
250
|
+
-------
|
|
251
|
+
bool
|
|
252
|
+
True if the molecule is radical, False otherwise.
|
|
253
|
+
|
|
254
|
+
Warnings
|
|
255
|
+
--------
|
|
256
|
+
This radical check is incomplete. If the number of unpaired electrons is even, it is not considered a radical.
|
|
257
|
+
"""
|
|
258
|
+
# FIXME: This radical check is incomplete. If the number of unpaired electrons is even, it is not considered a radical.
|
|
259
|
+
warnings.warn('This radical check is incomplete. If the number of unpaired electrons is even, it is not considered a radical.')
|
|
260
|
+
elements = 0
|
|
261
|
+
for symbol in self._symbols:
|
|
262
|
+
elements += self.ELEMENTS_NUM[symbol]
|
|
263
|
+
|
|
264
|
+
if elements % 2 == 0:
|
|
265
|
+
return False
|
|
266
|
+
else:
|
|
267
|
+
return True
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: yu-mcal
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Program for the calculation of mobility tensor for organic semiconductor crystals
|
|
5
|
+
Author: Koki Ozawa
|
|
6
|
+
Author-email: Hiroyuki Matsui <h-matsui@yz.yamagata-u.ac.jp>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025 Hiroyuki Matsui
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Keywords: mobility,mobility tensor,organic semiconductor,reorganization energy,transfer integral
|
|
30
|
+
Classifier: Development Status :: 4 - Beta
|
|
31
|
+
Classifier: Intended Audience :: Education
|
|
32
|
+
Classifier: Intended Audience :: Science/Research
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
39
|
+
Classifier: Topic :: Scientific/Engineering
|
|
40
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
41
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
42
|
+
Requires-Python: >=3.9
|
|
43
|
+
Requires-Dist: numpy>=2.0.2
|
|
44
|
+
Requires-Dist: pandas>=2.3.3
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# mcal: Program for the calculation of mobility tensor for organic semiconductor crystals
|
|
48
|
+
[](https://www.python.org)
|
|
49
|
+
[](https://opensource.org/licenses/MIT)
|
|
50
|
+
|
|
51
|
+
# Overview
|
|
52
|
+
`mcal.py` is a tool for calculating mobility tensors of organic semiconductors. It calculates transfer integrals and reorganization energy from crystal structures, and determines mobility tensors considering anisotropy and path continuity.
|
|
53
|
+
|
|
54
|
+
# Requirements
|
|
55
|
+
* Python 3.9 or newer
|
|
56
|
+
* NumPy
|
|
57
|
+
* Pandas
|
|
58
|
+
* Gaussian 09 or 16
|
|
59
|
+
|
|
60
|
+
# Important notice
|
|
61
|
+
* The path of the Gaussian must be set.
|
|
62
|
+
|
|
63
|
+
# Installation
|
|
64
|
+
```bash
|
|
65
|
+
pip install yu-mcal
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
## Verify Installation
|
|
70
|
+
|
|
71
|
+
After installation, you can verify by running:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
mcal --help
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
# mcal Usage Manual
|
|
78
|
+
|
|
79
|
+
## Basic Usage
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
mcal <cif_filename or pkl_filenname> <osc_type> [options]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Required Arguments
|
|
86
|
+
|
|
87
|
+
- `cif_filename`: Path to the CIF file
|
|
88
|
+
- `pkl_filename`: Path to the pickle file
|
|
89
|
+
- `osc_type`: Organic semiconductor type
|
|
90
|
+
- `p`: p-type semiconductor (uses HOMO level)
|
|
91
|
+
- `n`: n-type semiconductor (uses LUMO level)
|
|
92
|
+
|
|
93
|
+
### Basic Examples
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Calculate as p-type semiconductor
|
|
97
|
+
mcal xxx.cif p
|
|
98
|
+
|
|
99
|
+
# Calculate as n-type semiconductor
|
|
100
|
+
mcal xxx.cif n
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Options
|
|
104
|
+
|
|
105
|
+
### Calculation Settings
|
|
106
|
+
|
|
107
|
+
#### `-M, --method <method>`
|
|
108
|
+
Specify the calculation method used in Gaussian calculations.
|
|
109
|
+
- **Default**: `B3LYP/6-31G(d,p)`
|
|
110
|
+
- **Example**: `mcal xxx.cif p -M "B3LYP/6-31G(d)"`
|
|
111
|
+
|
|
112
|
+
#### `-c, --cpu <number>`
|
|
113
|
+
Specify the number of CPUs to use.
|
|
114
|
+
- **Default**: `4`
|
|
115
|
+
- **Example**: `mcal xxx.cif p -c 8`
|
|
116
|
+
|
|
117
|
+
#### `-m, --mem <memory>`
|
|
118
|
+
Specify the amount of memory in GB.
|
|
119
|
+
- **Default**: `10`
|
|
120
|
+
- **Example**: `mcal xxx.cif p -m 16`
|
|
121
|
+
|
|
122
|
+
#### `-g, --g09`
|
|
123
|
+
Use Gaussian 09 (default is Gaussian 16).
|
|
124
|
+
- **Example**: `mcal xxx.cif p -g`
|
|
125
|
+
|
|
126
|
+
### Calculation Control
|
|
127
|
+
|
|
128
|
+
#### `-r, --read`
|
|
129
|
+
Read results from existing log files without executing Gaussian.
|
|
130
|
+
- **Example**: `mcal xxx.cif p -r`
|
|
131
|
+
|
|
132
|
+
#### `-rp, --read_pickle`
|
|
133
|
+
Read results from existing pickle file without executing calculations.
|
|
134
|
+
- **Example**: `mcal xxx_result.pkl p -rp`
|
|
135
|
+
|
|
136
|
+
#### `--resume`
|
|
137
|
+
Resume calculation using existing results if log files terminated normally.
|
|
138
|
+
- **Example**: `mcal xxx.cif p --resume`
|
|
139
|
+
|
|
140
|
+
#### `--fullcal`
|
|
141
|
+
Disable speedup processing using moment of inertia and distance between centers of weight, and calculate transfer integrals for all pairs.
|
|
142
|
+
- **Example**: `mcal xxx.cif p --fullcal`
|
|
143
|
+
|
|
144
|
+
#### `--cellsize <number>`
|
|
145
|
+
Specify the number of unit cells to expand in each direction around the central unit cell for transfer integral calculations.
|
|
146
|
+
- **Default**: `2` (creates 5×5×5 supercell)
|
|
147
|
+
- **Examples**:
|
|
148
|
+
- `mcal xxx.cif p --cellsize 1` (creates 3×3×3 supercell)
|
|
149
|
+
- `mcal xxx.cif p --cellsize 3` (creates 7×7×7 supercell)
|
|
150
|
+
|
|
151
|
+
### Output Settings
|
|
152
|
+
|
|
153
|
+
#### `-p, --pickle`
|
|
154
|
+
Save calculation results to a pickle file.
|
|
155
|
+
- **Example**: `mcal xxx.cif p -p`
|
|
156
|
+
|
|
157
|
+
### Diffusion Coefficient Calculation Methods
|
|
158
|
+
|
|
159
|
+
#### `--mc`
|
|
160
|
+
Calculate diffusion coefficient tensor using kinetic Monte Carlo method.
|
|
161
|
+
- **Example**: `mcal xxx.cif p --mc`
|
|
162
|
+
|
|
163
|
+
#### `--ode`
|
|
164
|
+
Calculate diffusion coefficient tensor using Ordinary Differential Equation method.
|
|
165
|
+
- **Example**: `mcal xxx.cif p --ode`
|
|
166
|
+
|
|
167
|
+
## Practical Usage Examples
|
|
168
|
+
|
|
169
|
+
### Basic Calculations
|
|
170
|
+
```bash
|
|
171
|
+
# Calculate mobility of p-type xxx
|
|
172
|
+
mcal xxx.cif p
|
|
173
|
+
|
|
174
|
+
# Use 8 CPUs and 16GB memory
|
|
175
|
+
mcal xxx.cif p -c 8 -m 16
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### High-Precision Calculations
|
|
179
|
+
```bash
|
|
180
|
+
# Calculate transfer integrals for all pairs (high precision, time-consuming)
|
|
181
|
+
mcal xxx.cif p --fullcal
|
|
182
|
+
|
|
183
|
+
# Use larger supercell to widen transfer integral calculation range
|
|
184
|
+
mcal xxx.cif p --cellsize 3
|
|
185
|
+
|
|
186
|
+
# Use different basis set
|
|
187
|
+
mcal xxx.cif p -M "B3LYP/6-311G(d,p)"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Reusing Results
|
|
191
|
+
```bash
|
|
192
|
+
# Read from existing calculation results
|
|
193
|
+
mcal xxx.cif p -r
|
|
194
|
+
|
|
195
|
+
# Read from existing pickle file
|
|
196
|
+
mcal xxx_result.pkl p -rp
|
|
197
|
+
|
|
198
|
+
# Resume interrupted calculation
|
|
199
|
+
mcal xxx.cif p --resume
|
|
200
|
+
|
|
201
|
+
# Save results to pickle file
|
|
202
|
+
mcal xxx.cif p -p
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Comparing Diffusion Coefficients
|
|
206
|
+
```bash
|
|
207
|
+
# Compare with normal calculation + kinetic Monte Carlo + ODE methods
|
|
208
|
+
mcal xxx.cif p --mc --ode
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Output
|
|
212
|
+
|
|
213
|
+
### Standard Output
|
|
214
|
+
- Reorganization energy
|
|
215
|
+
- Transfer integrals for each pair
|
|
216
|
+
- Diffusion coefficient tensor
|
|
217
|
+
- Mobility tensor
|
|
218
|
+
- Eigenvalues and eigenvectors of mobility
|
|
219
|
+
|
|
220
|
+
## Notes
|
|
221
|
+
|
|
222
|
+
1. **Calculation Time**: Calculation time varies significantly depending on the number of molecules and cell size
|
|
223
|
+
2. **Memory Usage**: Ensure sufficient memory for large systems
|
|
224
|
+
3. **Gaussian Installation**: Gaussian 09 or Gaussian 16 is required
|
|
225
|
+
4. **Dependencies**: Make sure all required Python libraries are installed
|
|
226
|
+
|
|
227
|
+
## Troubleshooting
|
|
228
|
+
|
|
229
|
+
### If calculation stops midway
|
|
230
|
+
```bash
|
|
231
|
+
# Resume with --resume option
|
|
232
|
+
mcal xxx.cif p --resume
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Memory shortage error
|
|
236
|
+
```bash
|
|
237
|
+
# Increase memory amount
|
|
238
|
+
mcal xxx.cif p -m 32
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### To reduce calculation time
|
|
242
|
+
```bash
|
|
243
|
+
# Enable speedup processing (default)
|
|
244
|
+
mcal xxx.cif p
|
|
245
|
+
|
|
246
|
+
# Use smaller supercell for faster calculation
|
|
247
|
+
mcal xxx.cif p --cellsize 1
|
|
248
|
+
|
|
249
|
+
# Increase number of CPUs
|
|
250
|
+
mcal xxx.cif p -c 16
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
# Authors
|
|
254
|
+
[Matsui Laboratory, Research Center for Organic Electronics (ROEL), Yamagata University](https://matsui-lab.yz.yamagata-u.ac.jp/index-e.html)
|
|
255
|
+
Hiroyuki Matsui, Koki Ozawa
|
|
256
|
+
Email: h-matsui[at]yz.yamagata-u.ac.jp
|
|
257
|
+
Please replace [at] with @
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
mcal/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
2
|
+
mcal/mcal.py,sha256=eL57d_vm8Rf0kAZwVgRphRvIpEB9_u1NaBSPUs_wvlI,28648
|
|
3
|
+
mcal/calculations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
mcal/calculations/hopping_mobility_model.py,sha256=kjE_07nC4hbhWV5B37G0rtsgPqjBuHP0wsJ53rXoPOQ,13180
|
|
5
|
+
mcal/calculations/rcal.py,sha256=CH3iV18KTM8xU7M7zKR3e1m67GbJLH8zi0j50TsUXLE,13500
|
|
6
|
+
mcal/calculations/tcal.py,sha256=td09qG28PGDOxY_lQDwKk0W0iReh8RF6_dd3kjN62QE,39979
|
|
7
|
+
mcal/constants/element_properties.csv,sha256=_Yanl713VZQaAqPYoLNn-hXDdg01ZfkYsCLQ1SQSX8w,4073
|
|
8
|
+
mcal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
mcal/utils/cif_reader.py,sha256=nhvk7y8ix4yKhyKjDaw2Luotw6YFMGbGCaeBVP6Qd5E,22901
|
|
10
|
+
mcal/utils/gaus_log_reader.py,sha256=nNIgBae9hRUgpmNF7eIC5LOENSo6NQmuckMM4A3HAa8,3159
|
|
11
|
+
mcal/utils/gjf_maker.py,sha256=Kkh_gNcifFfhTikZar6SzoNJ7AyEBiCBXJTQkHxHX-0,8193
|
|
12
|
+
yu_mcal-0.1.0.dist-info/METADATA,sha256=oBAS8ZHFduaZrGTw-O9-reJlUGEn-VJNPxbl4iQvS7E,7630
|
|
13
|
+
yu_mcal-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
yu_mcal-0.1.0.dist-info/entry_points.txt,sha256=_0xZR3t9qvFSd9L6Iot03NixVLxXioEY19L6w3Fs1Ew,40
|
|
15
|
+
yu_mcal-0.1.0.dist-info/licenses/LICENSE,sha256=JP8vm7gYE73jLgnMFTOLNo_RnH88RrB4Goyh7H_muto,1072
|
|
16
|
+
yu_mcal-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Hiroyuki Matsui
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|