FEM-Design 0.0.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.
- FEM_Design-0.0.1.dist-info/LICENSE +21 -0
- FEM_Design-0.0.1.dist-info/METADATA +66 -0
- FEM_Design-0.0.1.dist-info/RECORD +14 -0
- FEM_Design-0.0.1.dist-info/WHEEL +5 -0
- FEM_Design-0.0.1.dist-info/top_level.txt +1 -0
- femdesign/__init__.py +0 -0
- femdesign/calculate/__init__.py +0 -0
- femdesign/calculate/analysis.py +418 -0
- femdesign/calculate/command.py +445 -0
- femdesign/calculate/fdscript.py +87 -0
- femdesign/comunication.py +454 -0
- femdesign/database.py +63 -0
- femdesign/utilities/__init__.py +0 -0
- femdesign/utilities/filehelper.py +40 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from time import sleep
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from femdesign.calculate.analysis import Analysis, Design
|
|
7
|
+
from femdesign.calculate.fdscript import Fdscript
|
|
8
|
+
from femdesign.utilities.filehelper import OutputFileHelper
|
|
9
|
+
from femdesign.calculate.command import DesignModule, CmdUser, CmdCalculation, CmdListGen, CmdOpen, CmdProjDescr, CmdSave
|
|
10
|
+
|
|
11
|
+
import win32file
|
|
12
|
+
import win32pipe
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
FEM - Design usage with pipe
|
|
18
|
+
|
|
19
|
+
To initiate :
|
|
20
|
+
1 : create a WIN32 named pipe for duplex mode, message oriented
|
|
21
|
+
1a : optional : create another pipe for back channel, named appending 'b'.
|
|
22
|
+
2 : launch FD with command line
|
|
23
|
+
/ p Name
|
|
24
|
+
passing the name you used at creation.FD will open it right at start and exit if can't
|
|
25
|
+
after successful open it listens to commands while the usual interface is active
|
|
26
|
+
you can combine it with the windowless / minimized mode to hide the window
|
|
27
|
+
it also attaches to the back channel pipe at this moment, if unable, all output is permanently disabled
|
|
28
|
+
3 : send commands through the pipe
|
|
29
|
+
4 : FD will exit if 'exit' command received or the pipe is closed on this end
|
|
30
|
+
|
|
31
|
+
FD only reads the main pipe and only writes the back channel(if supplied), allowing this end to never
|
|
32
|
+
read.While the pipe is duplexand can be used in both direction, if it gets clogged in
|
|
33
|
+
one direction(by not reading what the other end sends), the write can get blocked too.
|
|
34
|
+
The document recommends using another pipe for a back channel.
|
|
35
|
+
By default nothing is written to the back channel, you need to set output level or commands with implicit reply.
|
|
36
|
+
FD buffers all outgoing messages till they can be sent over, if this end is lazy to read it will not clog,
|
|
37
|
+
however they will accumulate in memory.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
Messages are text in 9bit ANSI(codepage), limited to 4096 bytes
|
|
42
|
+
|
|
43
|
+
The command format is
|
|
44
|
+
[!]cmd[space][args]
|
|
45
|
+
there is no delimiter at the end, the pipe message counts.
|
|
46
|
+
FD reads the pipe immediatelyand puts the commands in a queue.The queue is processed when it's READYSTATE
|
|
47
|
+
for another command, finishing execution of the previous or a running script.
|
|
48
|
+
The !requests out - of bound execution.That is not suppoerted by very command and mainly
|
|
49
|
+
serves to manipulate the queue itself, verbosity or check the communicaiton is alive.
|
|
50
|
+
|
|
51
|
+
Commands:
|
|
52
|
+
|
|
53
|
+
exit
|
|
54
|
+
stop the FD process
|
|
55
|
+
|
|
56
|
+
detach
|
|
57
|
+
close the pipe and continue IN normal interface mode
|
|
58
|
+
|
|
59
|
+
clear[in | out]
|
|
60
|
+
flush the FD mesage queue for the direction, both without parameters
|
|
61
|
+
has no Effect on what is already issued to the pipe
|
|
62
|
+
|
|
63
|
+
echo[txt]
|
|
64
|
+
write txt to output
|
|
65
|
+
|
|
66
|
+
stat
|
|
67
|
+
write queueand processing status to output
|
|
68
|
+
|
|
69
|
+
v[N]
|
|
70
|
+
set verbosity control (bits)
|
|
71
|
+
1: enable basic output
|
|
72
|
+
2: echo all INPUT commands
|
|
73
|
+
4: FD log Lines
|
|
74
|
+
8: script log lines
|
|
75
|
+
*16: calculation window messages (except fortran)
|
|
76
|
+
*32: progress window title
|
|
77
|
+
|
|
78
|
+
echo and stat always cretes output, otherwise nothing is written aT V = 0
|
|
79
|
+
* not yet supported
|
|
80
|
+
|
|
81
|
+
run[scriptfile]
|
|
82
|
+
execute script as from tools / run script menu
|
|
83
|
+
*Note: When using Unicode commands, add the suffix 'UTF8'. E.g.: "runUTF8 [scriptfile]".
|
|
84
|
+
|
|
85
|
+
cmd[command]
|
|
86
|
+
execute command as if typed into the command window -- No warranty!!!
|
|
87
|
+
*Note: When using Unicode commands, add the suffix 'UTF8'. E.g.: "cmdUTF8 [command]".
|
|
88
|
+
|
|
89
|
+
esc
|
|
90
|
+
press Escape during calculation to break it
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def GetElapsedTime(start_time):
|
|
96
|
+
return (datetime.now() - start_time).total_seconds()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class _FdConnect:
|
|
100
|
+
|
|
101
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
102
|
+
self.Detach()
|
|
103
|
+
self.ClosePipe()
|
|
104
|
+
|
|
105
|
+
def __init__(self, pipe_name="FdPipe1"):
|
|
106
|
+
"""
|
|
107
|
+
Creating fd pipe
|
|
108
|
+
One fd connection for the life of the fem design until closure.
|
|
109
|
+
It could be more than one with given uniqe pipe_name.
|
|
110
|
+
"""
|
|
111
|
+
self.pipe_name = pipe_name
|
|
112
|
+
self.pipe_send = self._CreatePipe(pipe_name)
|
|
113
|
+
self.pipe_read = self._CreatePipe(f"{pipe_name}b")
|
|
114
|
+
self.start_time = None
|
|
115
|
+
self._log_message_history = []
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def _CreatePipe(name):
|
|
119
|
+
return win32pipe.CreateNamedPipe(
|
|
120
|
+
r"\\.\pipe\%s" % name,
|
|
121
|
+
win32pipe.PIPE_ACCESS_DUPLEX,
|
|
122
|
+
win32pipe.PIPE_TYPE_MESSAGE
|
|
123
|
+
| win32pipe.PIPE_READMODE_MESSAGE
|
|
124
|
+
| win32pipe.PIPE_NOWAIT,
|
|
125
|
+
win32pipe.PIPE_UNLIMITED_INSTANCES,
|
|
126
|
+
4096,
|
|
127
|
+
4096,
|
|
128
|
+
0,
|
|
129
|
+
None,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def _ConnectPipe(self, timeout=60):
|
|
133
|
+
start_time = datetime.now()
|
|
134
|
+
while GetElapsedTime(start_time) <= timeout:
|
|
135
|
+
try:
|
|
136
|
+
win32pipe.ConnectNamedPipe(self.pipe_send, None)
|
|
137
|
+
win32pipe.ConnectNamedPipe(self.pipe_read, None)
|
|
138
|
+
return
|
|
139
|
+
except:
|
|
140
|
+
sleep(0.5)
|
|
141
|
+
raise TimeoutError(f"Program not connected in {timeout} second")
|
|
142
|
+
|
|
143
|
+
def Start(self, fd_path, timeout=60):
|
|
144
|
+
"""
|
|
145
|
+
Start and connect of fem-design with specified path
|
|
146
|
+
"""
|
|
147
|
+
self.process = subprocess.Popen([fd_path, "/p", self.pipe_name])
|
|
148
|
+
self._ConnectPipe(timeout=timeout)
|
|
149
|
+
|
|
150
|
+
def _Read(self):
|
|
151
|
+
"""
|
|
152
|
+
Read one message if exists
|
|
153
|
+
"""
|
|
154
|
+
try:
|
|
155
|
+
return win32file.ReadFile(self.pipe_read, 4096)[1].decode()
|
|
156
|
+
except Exception as err:
|
|
157
|
+
if err.winerror == 232: # Error text (The pipe is being closed.) Pipe is empty
|
|
158
|
+
return None
|
|
159
|
+
elif err.winerror == 109: # Error text (The pipe has been ended.) Conecction lost
|
|
160
|
+
raise AssertionError("Connection lost")
|
|
161
|
+
else:
|
|
162
|
+
raise err
|
|
163
|
+
|
|
164
|
+
def ReadAll(self):
|
|
165
|
+
"""
|
|
166
|
+
Read all existing message
|
|
167
|
+
"""
|
|
168
|
+
results = []
|
|
169
|
+
while True:
|
|
170
|
+
result = self._Read()
|
|
171
|
+
if result == None:
|
|
172
|
+
return "\n".join(results)
|
|
173
|
+
results.append(result)
|
|
174
|
+
self._log_message_history.append(result)
|
|
175
|
+
|
|
176
|
+
def GetLogMessageHistory(self):
|
|
177
|
+
"""
|
|
178
|
+
Return all collected message
|
|
179
|
+
"""
|
|
180
|
+
return self._log_message_history
|
|
181
|
+
|
|
182
|
+
def Send(self, message):
|
|
183
|
+
"""
|
|
184
|
+
Send one message
|
|
185
|
+
"""
|
|
186
|
+
try:
|
|
187
|
+
win32file.WriteFile(self.pipe_send, message.encode())
|
|
188
|
+
except Exception as err:
|
|
189
|
+
if err.winerror == 232: # Error text (The pipe is being closed.) Connection lost
|
|
190
|
+
raise AssertionError("Connection lost")
|
|
191
|
+
else:
|
|
192
|
+
raise err
|
|
193
|
+
|
|
194
|
+
def SendAndReceive(self, message, timeout=None):
|
|
195
|
+
"""
|
|
196
|
+
Complete workflow of send message and receive answer until timeout
|
|
197
|
+
"""
|
|
198
|
+
self.Send(message)
|
|
199
|
+
start_time = self.start_time or datetime.now()
|
|
200
|
+
while timeout == None or GetElapsedTime(start_time) <= timeout:
|
|
201
|
+
result = self.ReadAll()
|
|
202
|
+
if result:
|
|
203
|
+
return result
|
|
204
|
+
sleep(0.5)
|
|
205
|
+
raise TimeoutError(f"Program not responding after {timeout} second")
|
|
206
|
+
|
|
207
|
+
def Stat(self, timeout=None):
|
|
208
|
+
"""
|
|
209
|
+
Return queueand processing status
|
|
210
|
+
"""
|
|
211
|
+
return self.SendAndReceive("stat", timeout=timeout)
|
|
212
|
+
|
|
213
|
+
def LogLevel(self, n):
|
|
214
|
+
"""
|
|
215
|
+
Set log level
|
|
216
|
+
verbosity control (bits)
|
|
217
|
+
1: enable basic output
|
|
218
|
+
2: echo all INPUT commands
|
|
219
|
+
4: FD log Lines
|
|
220
|
+
8: script log lines
|
|
221
|
+
*16: calculation window messages (except fortran)
|
|
222
|
+
*32: progress window title
|
|
223
|
+
|
|
224
|
+
echo and stat always creates output, otherwise nothing is written aT V = 0
|
|
225
|
+
* not yet supported
|
|
226
|
+
"""
|
|
227
|
+
return self.Send(f"v {n}")
|
|
228
|
+
|
|
229
|
+
def RunScript(self, path, timeout=None):
|
|
230
|
+
"""
|
|
231
|
+
Execute script as from tools / run script menu
|
|
232
|
+
"""
|
|
233
|
+
self.Send(f"runUTF8 {path}")
|
|
234
|
+
self.start_time = datetime.now()
|
|
235
|
+
while timeout == None or GetElapsedTime(self.start_time) <= timeout:
|
|
236
|
+
sleep(0.1)
|
|
237
|
+
if "script idle" in self.Stat(timeout=timeout):
|
|
238
|
+
self.start_time = None
|
|
239
|
+
return
|
|
240
|
+
raise TimeoutError(f"Too long script run time after {timeout} second")
|
|
241
|
+
|
|
242
|
+
def Cmd(self, cmd_text):
|
|
243
|
+
"""
|
|
244
|
+
Execute command as if typed into the command window -- No warranty!!!
|
|
245
|
+
"""
|
|
246
|
+
self.Send(f"cmdUTF8 {cmd_text}")
|
|
247
|
+
|
|
248
|
+
def Esc(self):
|
|
249
|
+
"""
|
|
250
|
+
Press Escape during calculation to break it
|
|
251
|
+
"""
|
|
252
|
+
self.Send("esc")
|
|
253
|
+
|
|
254
|
+
def Exit(self):
|
|
255
|
+
"""
|
|
256
|
+
Close fem-design
|
|
257
|
+
"""
|
|
258
|
+
self.Send("exit")
|
|
259
|
+
|
|
260
|
+
def Detach(self):
|
|
261
|
+
"""
|
|
262
|
+
Disconnect from pipe and close it. You can't reattach to fem-design.
|
|
263
|
+
It must be outside of KillProgramIfExists scope.
|
|
264
|
+
"""
|
|
265
|
+
self.Send("detach")
|
|
266
|
+
sleep(2)
|
|
267
|
+
self.ClosePipe()
|
|
268
|
+
|
|
269
|
+
def ClosePipe(self):
|
|
270
|
+
"""
|
|
271
|
+
Regular closing of fd pipe
|
|
272
|
+
"""
|
|
273
|
+
win32file.CloseHandle(self.pipe_send)
|
|
274
|
+
win32file.CloseHandle(self.pipe_read)
|
|
275
|
+
|
|
276
|
+
def KillProgramIfExists(self):
|
|
277
|
+
"""
|
|
278
|
+
Kill program if exists
|
|
279
|
+
"""
|
|
280
|
+
if not (self.process.poll()):
|
|
281
|
+
try:
|
|
282
|
+
self.process.kill()
|
|
283
|
+
except WindowsError:
|
|
284
|
+
print("Program gone in meantime")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
class Verbosity(Enum):
|
|
288
|
+
BASIC = 1
|
|
289
|
+
ECHO_ALL_INPUT_COMMANDS = 2
|
|
290
|
+
FD_LOG_LINES = 4
|
|
291
|
+
SCRIPT_LOG_LINES = 8
|
|
292
|
+
CALCULATION_WINDOW_MESSAGES = 16
|
|
293
|
+
PROGRESS_WINDOW_TITLE = 32
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
## define a private class
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class FemDesignConnection(_FdConnect):
|
|
300
|
+
def __init__(self,
|
|
301
|
+
fd_path : str = r"C:\Program Files\StruSoft\FEM-Design 23\fd3dstruct.exe",
|
|
302
|
+
pipe_name : str ="FdPipe1",
|
|
303
|
+
verbose : Verbosity = Verbosity.SCRIPT_LOG_LINES,
|
|
304
|
+
output_dir : str = None,
|
|
305
|
+
minimized : bool = False,):
|
|
306
|
+
super().__init__(pipe_name)
|
|
307
|
+
|
|
308
|
+
self._output_dir = output_dir
|
|
309
|
+
|
|
310
|
+
os.environ["FD_NOLOGO"] = "1"
|
|
311
|
+
|
|
312
|
+
if minimized:
|
|
313
|
+
os.environ["FD_NOGUI"] = "1"
|
|
314
|
+
|
|
315
|
+
self.Start(fd_path)
|
|
316
|
+
self.LogLevel(verbose)
|
|
317
|
+
|
|
318
|
+
@property
|
|
319
|
+
def output_dir(self):
|
|
320
|
+
if self._output_dir == None:
|
|
321
|
+
return os.path.join(os.getcwd(), "FEM-Design API")
|
|
322
|
+
else:
|
|
323
|
+
return os.path.abspath(self._output_dir)
|
|
324
|
+
|
|
325
|
+
@output_dir.setter
|
|
326
|
+
def output_dir(self, value):
|
|
327
|
+
self._output_dir = os.path.abspath(value)
|
|
328
|
+
if not os.path.exists(value):
|
|
329
|
+
os.makedirs(os.path.abspath(value))
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def RunScript(self, fdscript : Fdscript, file_name : str = "script"):
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
fdscript (Fdscript): fdscript object to run
|
|
337
|
+
file_name (str, optional): file name to save the script. Defaults to "script".
|
|
338
|
+
"""
|
|
339
|
+
path = OutputFileHelper.GetFdscriptFilePath(self.output_dir, file_name)
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
fdscript.serialise_to_file(path)
|
|
343
|
+
super().RunScript(path)
|
|
344
|
+
|
|
345
|
+
def RunAnalysis(self, analysis : Analysis):
|
|
346
|
+
"""Run analysis
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
analysis (analysis.Analysis): analysis object
|
|
350
|
+
"""
|
|
351
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
352
|
+
|
|
353
|
+
fdscript = Fdscript(log, [CmdUser.ResMode(), CmdCalculation(analysis)])
|
|
354
|
+
self.RunScript(fdscript, "analysis")
|
|
355
|
+
|
|
356
|
+
def RunDesign(self, designMode : DesignModule , design : Design):
|
|
357
|
+
"""Run design
|
|
358
|
+
|
|
359
|
+
Args:
|
|
360
|
+
designMode (DesignModule): design module
|
|
361
|
+
design (analysis.Design): design object
|
|
362
|
+
"""
|
|
363
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
364
|
+
|
|
365
|
+
fdscript = Fdscript(log, [CmdUser(designMode.to_user()), CmdCalculation(design)])
|
|
366
|
+
self.RunScript(fdscript, "design")
|
|
367
|
+
|
|
368
|
+
def SetProjectDescription(self, project_name : str = "", project_description : str = "", designer : str = "", signature : str = "", comment : str = "", additional_info : dict = None, read : bool = False, reset : bool = False):
|
|
369
|
+
"""Set project description
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
project_name (str): project name
|
|
373
|
+
project_description (str): project description
|
|
374
|
+
designer (str): designer
|
|
375
|
+
signature (str): signature
|
|
376
|
+
comment (str): comment
|
|
377
|
+
additional_info (dict): define key-value user data. Defaults to None.
|
|
378
|
+
read (bool, optional): read the project settings. Value will be store in the clipboard. Defaults to False.
|
|
379
|
+
reset (bool, optional): reset the project settings. Defaults to False.
|
|
380
|
+
|
|
381
|
+
Examples
|
|
382
|
+
--------
|
|
383
|
+
>>> pipe = FemDesignConnection(fd_path= r"C:\Program Files\StruSoft\FEM-Design 23\\fd3dstruct.exe",
|
|
384
|
+
minimized= False)
|
|
385
|
+
>>> pipe.SetProjectDescription(project_name="Amazing project",
|
|
386
|
+
project_description="Created through Python",
|
|
387
|
+
designer="Marco Pellegrino Engineer",
|
|
388
|
+
signature="MP",
|
|
389
|
+
comment="Wish for the best",
|
|
390
|
+
project_parameters={"italy": "amazing", "sweden": "amazing_too"})
|
|
391
|
+
|
|
392
|
+
"""
|
|
393
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
394
|
+
|
|
395
|
+
cmd_project = CmdProjDescr(project_name, project_description, designer, signature, comment, additional_info, read, reset)
|
|
396
|
+
fdscript = Fdscript(log, [cmd_project])
|
|
397
|
+
self.RunScript(fdscript, "project_description")
|
|
398
|
+
|
|
399
|
+
def Save(self, file_name : str):
|
|
400
|
+
"""Save the project
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
file_name (str): name of the file to save
|
|
404
|
+
|
|
405
|
+
Examples
|
|
406
|
+
--------
|
|
407
|
+
>>> pipe = FemDesignConnection(fd_path= "C:\Program Files\StruSoft\FEM-Design 23\\fd3dstruct.exe",
|
|
408
|
+
minimized= False)
|
|
409
|
+
>>> pipe.Save(r"outputFile.str")
|
|
410
|
+
>>> pipe.Save(r"outputFile.struxml")
|
|
411
|
+
"""
|
|
412
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
413
|
+
|
|
414
|
+
cmd_save = CmdSave(file_name)
|
|
415
|
+
|
|
416
|
+
fdscript = Fdscript(log, [cmd_save])
|
|
417
|
+
self.RunScript(fdscript, "save")
|
|
418
|
+
|
|
419
|
+
def Open(self, file_name : str):
|
|
420
|
+
"""Open a model from file
|
|
421
|
+
|
|
422
|
+
Args:
|
|
423
|
+
file_name (str): file path to open
|
|
424
|
+
|
|
425
|
+
Raises:
|
|
426
|
+
ValueError: extension must be .struxml or .str
|
|
427
|
+
FileNotFoundError: file not found
|
|
428
|
+
"""
|
|
429
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
430
|
+
|
|
431
|
+
if not file_name.endswith(".struxml") and not file_name.endswith(".str"):
|
|
432
|
+
raise ValueError(f"File {file_name} must have extension .struxml or .str")
|
|
433
|
+
if not os.path.exists(file_name):
|
|
434
|
+
raise FileNotFoundError(f"File {file_name} not found")
|
|
435
|
+
|
|
436
|
+
cmd_open = CmdOpen(file_name)
|
|
437
|
+
fdscript = Fdscript(log, [cmd_open])
|
|
438
|
+
self.RunScript(fdscript, "open")
|
|
439
|
+
|
|
440
|
+
def SetVerbosity(self, verbosity : Verbosity):
|
|
441
|
+
super().LogLevel(verbosity.value)
|
|
442
|
+
|
|
443
|
+
def GenerateListTables(self, bsc_file : str, csv_file : str = None):
|
|
444
|
+
log = OutputFileHelper.GetLogFilePath(self.output_dir)
|
|
445
|
+
|
|
446
|
+
cmd_results = CmdListGen(bsc_file, csv_file)
|
|
447
|
+
fdscript = Fdscript(log, [cmd_results])
|
|
448
|
+
self.RunScript(fdscript, "generate_list_tables")
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
## it does not work
|
|
452
|
+
def Disconnect(self):
|
|
453
|
+
super().Detach()
|
|
454
|
+
win32pipe.DisconnectNamedPipe(self.pipe_send)
|
femdesign/database.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import xml.etree.ElementTree as ET
|
|
2
|
+
import uuid
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
namespace = {'': 'urn:strusoft'}
|
|
6
|
+
|
|
7
|
+
class Database:
|
|
8
|
+
def __init__(self, country):
|
|
9
|
+
self.struxml_version = "01.00.000"
|
|
10
|
+
self.source_software = f"FEM-Design API SDK {self.get_version()}"
|
|
11
|
+
self.start_time = "1970-01-01T00:00:00.000"
|
|
12
|
+
self.end_time = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
|
|
13
|
+
self.guid = str(uuid.uuid4())
|
|
14
|
+
self.convert_id = "00000000-0000-0000-0000-000000000000"
|
|
15
|
+
self.standard = "EC"
|
|
16
|
+
self.country = country
|
|
17
|
+
self.end = ""
|
|
18
|
+
|
|
19
|
+
def get_version(self):
|
|
20
|
+
return "0.1.0"
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def eurocode(self):
|
|
24
|
+
return self._root.attrib["standard"]
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def country(self):
|
|
28
|
+
return self._root.attrib["country"]
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def source_software(self):
|
|
32
|
+
return self._root.attrib["source_software"]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def entities(self):
|
|
36
|
+
return self._root.findall(".//entities", namespace)
|
|
37
|
+
|
|
38
|
+
@property
|
|
39
|
+
def sections(self):
|
|
40
|
+
return self._root.findall(".//sections", namespace)
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def materials(self):
|
|
44
|
+
return self._root.findall(".//materials", namespace)
|
|
45
|
+
|
|
46
|
+
@property
|
|
47
|
+
def bars(self):
|
|
48
|
+
return self._root.findall(".//bar", namespace)
|
|
49
|
+
|
|
50
|
+
def serialise_to_xml(self):
|
|
51
|
+
return ET.tostring(self._root, encoding="UTF-8")
|
|
52
|
+
|
|
53
|
+
# private void Initialize(Country country)
|
|
54
|
+
# {
|
|
55
|
+
# this.StruxmlVersion = "01.00.000";
|
|
56
|
+
# this.SourceSoftware = $"FEM-Design API SDK {Assembly.GetExecutingAssembly().GetName().Version.ToString()}";
|
|
57
|
+
# this.StartTime = "1970-01-01T00:00:00.000";
|
|
58
|
+
# this.EndTime = System.DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss.fff", CultureInfo.InvariantCulture);
|
|
59
|
+
# this.Guid = System.Guid.NewGuid();
|
|
60
|
+
# this.ConvertId = "00000000-0000-0000-0000-000000000000";
|
|
61
|
+
# this.Standard = "EC";
|
|
62
|
+
# this.Country = country;
|
|
63
|
+
# this.End = "";
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import pathlib
|
|
3
|
+
## define a static class to help with file operations
|
|
4
|
+
class OutputFileHelper:
|
|
5
|
+
_scriptsDirectory = "scripts"
|
|
6
|
+
_resultsDirectory = "results"
|
|
7
|
+
_bscDirectory = "bsc"
|
|
8
|
+
|
|
9
|
+
_logFileName = "logfile.log"
|
|
10
|
+
_struxmlFileName = "model.struxml"
|
|
11
|
+
_strFileName = "model.str"
|
|
12
|
+
_docxFileName = "model.docx"
|
|
13
|
+
|
|
14
|
+
_fdscriptFileExtension = ".fdscript"
|
|
15
|
+
_bscFileExtension = ".bsc"
|
|
16
|
+
_csvFileExtension = ".csv"
|
|
17
|
+
|
|
18
|
+
_strFileExtension = ".str"
|
|
19
|
+
_struxmlFileExtension = ".struxml"
|
|
20
|
+
|
|
21
|
+
def GetLogFilePath(outputDirectory: str) -> str:
|
|
22
|
+
if not os.path.exists(outputDirectory):
|
|
23
|
+
os.makedirs(outputDirectory)
|
|
24
|
+
return os.path.abspath( os.path.join(outputDirectory, OutputFileHelper._logFileName) )
|
|
25
|
+
|
|
26
|
+
def GetFdscriptFilePath(outputDirectory: str, file_name: str = "script") -> str:
|
|
27
|
+
dir = os.path.join(outputDirectory, OutputFileHelper._scriptsDirectory)
|
|
28
|
+
if not os.path.exists(dir):
|
|
29
|
+
os.makedirs(dir)
|
|
30
|
+
|
|
31
|
+
path = os.path.abspath( os.path.join(dir, f"{file_name}" + OutputFileHelper._fdscriptFileExtension) )
|
|
32
|
+
return path
|
|
33
|
+
|
|
34
|
+
def GetBscFilePath(outputDirectory: str, file_name: str) -> str:
|
|
35
|
+
dir = os.path.join(outputDirectory, OutputFileHelper._scriptsDirectory, OutputFileHelper._bscDirectory)
|
|
36
|
+
if not os.path.exists(dir):
|
|
37
|
+
os.makedirs(dir)
|
|
38
|
+
|
|
39
|
+
path = os.path.abspath( os.path.join(dir, f"{file_name}" + OutputFileHelper._bscFileExtension) )
|
|
40
|
+
return path
|