Skip to content

Commit fbdbcad

Browse files
committed
Merge remote-tracking branch 'origin/zzqbranch'
2 parents 67994df + 62ba5c0 commit fbdbcad

File tree

6 files changed

+223
-5483
lines changed

6 files changed

+223
-5483
lines changed

examples/Explicit/output/ball_plate.k

Lines changed: 0 additions & 5466 deletions
This file was deleted.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ classifiers = [
2727

2828
dependencies = [
2929
"ansys-dpf-core>=0.7.2",
30-
"ansys-api-dyna==0.3.3",
30+
"ansys-api-dyna==0.3.5",
3131
]
3232

3333
[project.optional-dependencies]

src/ansys/dyna/core/pre/dynasolution.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,21 @@ def __init__(self, hostname="localhost", port="50051", server_path=""):
6262
check_valid_port(port)
6363
LOG.debug(f"Using default port {port}")
6464

65+
# start server locally
6566
if (hostname.lower() == "localhost" or hostname == LOCALHOST) and not DynaSolution.grpc_local_server_on():
6667
LOG.debug("Starting kwserver")
67-
# server_path = os.path.join(os.getcwd(), "../../src/ansys/dyna/core/pre/Server")
68-
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
69-
threadserver.setDaemon(True)
70-
threadserver.start()
68+
69+
if len(server_path) == 0:
70+
server_path = os.getenv("ANSYS_PYDYNA_PRE_SERVER_PATH")
71+
if server_path is None:
72+
print("Please set the environment variable for ANSYS_PYDYNA_PRE_SERVER_PATH")
73+
return False
74+
if os.path.isdir(server_path):
75+
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
76+
threadserver.setDaemon(True)
77+
threadserver.start()
78+
else:
79+
print("Failed to start pydyna pre server locally,Invalid server path!")
7180

7281
init_log("client.log")
7382
temp = hostname + ":" + str(port)

src/ansys/dyna/core/pre/launcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def launch_grpc(port=DYNAPRE_DEFAULT_PORT, ip=LOCALHOST, server_path=None) -> tu
9191
LOG.info(f"Running in {ip}:{port} the following command: '{command}'")
9292

9393
LOG.debug("the pre service starting in background.")
94-
process = subprocess.Popen(["python", "kwserver.py"], cwd=server_path, shell=True)
94+
process = subprocess.Popen("python kwserver.py", cwd=server_path, shell=True)
9595
process.wait()
9696
# while True:
9797
# pass

src/ansys/dyna/core/solver/dynasolver.py

Lines changed: 87 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
import sys
1212
import threading
1313

14-
from ansys.api.dyna.v0 import dynasolver_pb2, dynasolver_pb2_grpc
14+
from ansys.api.dyna.v0 import dynasolver_pb2
1515
import grpc
1616

1717
from . import grpc_tags as tag
18+
from .launcher import * # noqa : F403
1819

1920
#
2021
# Define our own exceptions
@@ -60,12 +61,46 @@ class DynaSolver:
6061
"""
6162

6263
# logger = None
63-
def __init__(self, hostname, port):
64+
def __init__(self, hostname, port, server_path=""):
6465
"""Create a client instance connected to the host name (or IP address) and port."""
6566
self.hostname = hostname
6667
self.port = port
67-
self.channel = grpc.insecure_channel(hostname + ":" + port)
68-
self.stub = dynasolver_pb2_grpc.DynaSolverCommStub(self.channel)
68+
69+
# start server locally
70+
if (hostname.lower() == "localhost" or hostname == LOCALHOST) and not DynaSolver.grpc_local_server_on():
71+
# LOG.debug("Starting solver server")
72+
73+
if len(server_path) == 0:
74+
server_path = os.getenv("ANSYS_PYDYNA_SOLVER_SERVER_PATH")
75+
if server_path is None:
76+
print("Please set the environment variable for ANSYS_PYDYNA_SOLVER_SERVER_PATH")
77+
return
78+
if os.path.isdir(server_path):
79+
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
80+
# threadserver.setDaemon(True)
81+
threadserver.start()
82+
waittime = 0
83+
while not DynaSolver.grpc_local_server_on():
84+
sleep(5)
85+
waittime += 5
86+
print(waittime)
87+
if waittime > 60:
88+
print("Failed to start pydyna solver server locally")
89+
break
90+
91+
else:
92+
print("Failed to start pydyna solver server locally,Invalid server path!")
93+
94+
temp = hostname + ":" + str(port)
95+
self.channel = grpc.insecure_channel(temp)
96+
try:
97+
grpc.channel_ready_future(self.channel).result(timeout=5)
98+
except grpc.FutureTimeoutError:
99+
logging.critical("Can not connect to Solver Server")
100+
sys.exit()
101+
logging.info("Connected to Solver Server...")
102+
# self.stub = dynasolver_pb2_grpc.DynaSolverCommStub(self.channel)
103+
self.stub = DynaSolverCommStub(self.channel)
69104
# if DynaSolver.logger is None:
70105
# DynaSolver.logger = logging.getLogger("DynaSolver")
71106
# DynaSolver.logger.setLevel(logging.INFO)
@@ -78,6 +113,22 @@ def __init__(self, hostname, port):
78113
# self.logger = DynaSolver.logger
79114
self.logger = logging.getLogger("DynaSolver")
80115

116+
@staticmethod
117+
def grpc_local_server_on() -> bool:
118+
"""Check if the server is launched locally.
119+
120+
Returns
121+
-------
122+
bool
123+
``True`` when successful, ``False`` when failed.
124+
"""
125+
channel = grpc.insecure_channel("localhost:5000")
126+
try:
127+
grpc.channel_ready_future(channel).result(timeout=5)
128+
except:
129+
return False
130+
return True
131+
81132
def _argcheck(self, cmd, ngiven, nrequired):
82133
"""Internally used routine for checking command argument counts
83134
when using the generic ``send`` method."""
@@ -247,12 +298,13 @@ def upload(self, fname):
247298
#
248299
# First packet contains the filename. The rest hold the contents.
249300
#
250-
self.logger.debug("upload: %s" % fname)
301+
# self.logger.debug("upload: %s" % fname)
251302
fsize = 0
252303

253304
def push_packets(fname):
254305
nonlocal fsize
255-
request = dynasolver_pb2.DynaSolverFileData()
306+
# request = dynasolver_pb2.DynaSolverFileData()
307+
request = DynaSolverFileData()
256308
# Only send the base file name, not the whole path!
257309
bfname = os.path.split(fname)[1]
258310
request.b = bytes(bfname, "utf-8")
@@ -261,7 +313,8 @@ def push_packets(fname):
261313
blocksize = 1000000
262314
n = blocksize
263315
while n == blocksize:
264-
request = dynasolver_pb2.DynaSolverFileData()
316+
# request = dynasolver_pb2.DynaSolverFileData()
317+
request = DynaSolverFileData()
265318
request.b = fp.read(blocksize)
266319
n = len(request.b)
267320
fsize = fsize + n
@@ -335,7 +388,8 @@ def run(self, args):
335388
Command line to pass to LS-DYNA.
336389
"""
337390
self.logger.debug("run: %s" % args)
338-
request = dynasolver_pb2.DynaSolverRelay()
391+
# request = dynasolver_pb2.DynaSolverRelay()
392+
request = DynaSolverRelay()
339393
request.tag = tag.RUN
340394
request.b = bytes(args, "utf-8")
341395
response = self.stub.send_request(request)
@@ -369,7 +423,7 @@ def setlc(self, lc, value):
369423
self._check_return(response)
370424
return
371425

372-
def start(self, nproc):
426+
def start(self, nproc, solver_fname=""):
373427
"""Start LS-DYNA.
374428
375429
The program starts and awaits further input. To begin a
@@ -385,14 +439,36 @@ def start(self, nproc):
385439
Number of cores (MPI ranks) to run.
386440
"""
387441
self.logger.debug("start: %d" % nproc)
388-
request = dynasolver_pb2.DynaSolverStart()
389-
request.exename = b"mppdyna"
442+
# request = dynasolver_pb2.DynaSolverStart()
443+
request = DynaSolverStart()
444+
# request.exename = b"mppdyna"
445+
request.exename = bytes(solver_fname, "utf-8")
390446
request.nproc = nproc
391447
response = self.stub.start_solver(request)
392448
if response.status == tag.RUNNING:
393449
raise RunningError("LSDYNA is already running")
394450
return
395451

452+
def start_locally(self, preset="MPP_DOUBLE", input="", nproc=1, memory=20):
453+
"""Begin execution with the given string as the command-line arguments.
454+
455+
Parameters
456+
----------
457+
args : str
458+
Command line to pass to LS-DYNA.
459+
"""
460+
461+
self.logger.debug("start: %d" % nproc)
462+
request = DynaSolverStartLocal()
463+
request.preset = bytes(preset, "utf-8")
464+
request.input = bytes(input, "utf-8")
465+
request.nproc = nproc
466+
request.memory = memory
467+
response = self.stub.start_solver_locally(request)
468+
# if response.status == tag.RUNNING:
469+
# raise RunningError("LSDYNA is already running")
470+
return
471+
396472
def switch(self, args):
397473
"""Send a "sense switch" to LS-DYNA.
398474
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
"""Module for launching the pydyna solver service locally."""
2+
3+
import socket
4+
import subprocess
5+
import threading
6+
7+
from ansys.dyna.core.pre import LOG
8+
9+
LOCALHOST = "127.0.0.1"
10+
DYNAPRE_DEFAULT_PORT = 50051
11+
12+
13+
def check_ports(port_range, ip="localhost"):
14+
"""Check the state of ports in a port range.
15+
16+
Parameters
17+
----------
18+
port_range :
19+
ip : str, optional
20+
IP address. The default is ``"localhost"``, in which case
21+
``"127.0.0.1"``is used.
22+
"""
23+
ports = {}
24+
for port in port_range:
25+
ports[port] = port_in_use(port, ip)
26+
return ports
27+
28+
29+
def port_in_use(port, host=LOCALHOST):
30+
"""
31+
Determine if a port is in use at a given host.
32+
33+
Parameters
34+
----------
35+
port : int
36+
Port.
37+
host :
38+
Host. The default is ``LOCALHOST``, in which case ``"127.0.0.1"``
39+
is used.
40+
41+
Returns
42+
-------
43+
``True`` when a port is in use at the given host, ``False`` otherwise.
44+
45+
Notes
46+
-----
47+
The port must "bind" the address. Just checking if a socket can be created
48+
is insufficient because it is possible to run into permission
49+
errors like this one:
50+
51+
"An attempt was made to access a socket in a way forbidden by its
52+
access permissions."
53+
"""
54+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
55+
try:
56+
sock.bind((host, port))
57+
return False
58+
except:
59+
return True
60+
61+
62+
def launch_grpc(port=DYNAPRE_DEFAULT_PORT, ip=LOCALHOST, server_path=None) -> tuple: # pragma: no cover
63+
"""
64+
Launch the solver service locally in gRPC mode.
65+
66+
Parameters
67+
----------
68+
port : int, optional
69+
Port to launch the solver service on. The default is ``DYNAPRE_DEFAULT_PORT``.
70+
The final port is the first port available after (or including) this
71+
port.
72+
ip : str, optional
73+
IP address. The default is ``LOCALHOST``, in which case ``"127.0.0.1"``
74+
is used.
75+
server_path : string, optional
76+
Path to the solver service. The default is ``None``.
77+
78+
Returns
79+
-------
80+
int
81+
Port number that the gRPC instance started on.
82+
"""
83+
LOG.debug("Starting 'launch_grpc'.")
84+
85+
command = "python kwserver.py"
86+
LOG.debug(f"Starting the solver service with command: {command}")
87+
88+
# env_vars = update_env_vars(add_env_vars, replace_env_vars)
89+
LOG.info(f"Running in {ip}:{port} the following command: '{command}'")
90+
91+
LOG.debug("the solver service starting in background.")
92+
process = subprocess.Popen("python server.py", cwd=server_path, shell=True)
93+
process.wait()
94+
return port
95+
96+
97+
class ServerThread(threading.Thread):
98+
"""Provides server thread properties.
99+
100+
Parameters
101+
----------
102+
threadID :
103+
port :
104+
ip :
105+
server_path :
106+
107+
"""
108+
109+
def __init__(self, threadID, port, ip, server_path):
110+
threading.Thread.__init__(self)
111+
self.threadID = threadID
112+
self.port = port
113+
self.ip = ip
114+
self.server_path = server_path
115+
self.process = None
116+
117+
def run(self):
118+
self.process = launch_grpc(ip=self.ip, port=self.port, server_path=self.server_path)
119+
120+
def termination(self):
121+
self.process.termination()

0 commit comments

Comments
 (0)