Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/zzqbranch'
Browse files Browse the repository at this point in the history
  • Loading branch information
wenhuiuy committed Nov 30, 2023
2 parents 67994df + 62ba5c0 commit fbdbcad
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 5,483 deletions.
5,466 changes: 0 additions & 5,466 deletions examples/Explicit/output/ball_plate.k

This file was deleted.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ classifiers = [

dependencies = [
"ansys-dpf-core>=0.7.2",
"ansys-api-dyna==0.3.3",
"ansys-api-dyna==0.3.5",
]

[project.optional-dependencies]
Expand Down
17 changes: 13 additions & 4 deletions src/ansys/dyna/core/pre/dynasolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,21 @@ def __init__(self, hostname="localhost", port="50051", server_path=""):
check_valid_port(port)
LOG.debug(f"Using default port {port}")

# start server locally
if (hostname.lower() == "localhost" or hostname == LOCALHOST) and not DynaSolution.grpc_local_server_on():
LOG.debug("Starting kwserver")
# server_path = os.path.join(os.getcwd(), "../../src/ansys/dyna/core/pre/Server")
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
threadserver.setDaemon(True)
threadserver.start()

if len(server_path) == 0:
server_path = os.getenv("ANSYS_PYDYNA_PRE_SERVER_PATH")
if server_path is None:
print("Please set the environment variable for ANSYS_PYDYNA_PRE_SERVER_PATH")
return False
if os.path.isdir(server_path):
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
threadserver.setDaemon(True)
threadserver.start()
else:
print("Failed to start pydyna pre server locally,Invalid server path!")

init_log("client.log")
temp = hostname + ":" + str(port)
Expand Down
2 changes: 1 addition & 1 deletion src/ansys/dyna/core/pre/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def launch_grpc(port=DYNAPRE_DEFAULT_PORT, ip=LOCALHOST, server_path=None) -> tu
LOG.info(f"Running in {ip}:{port} the following command: '{command}'")

LOG.debug("the pre service starting in background.")
process = subprocess.Popen(["python", "kwserver.py"], cwd=server_path, shell=True)
process = subprocess.Popen("python kwserver.py", cwd=server_path, shell=True)
process.wait()
# while True:
# pass
Expand Down
98 changes: 87 additions & 11 deletions src/ansys/dyna/core/solver/dynasolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
import sys
import threading

from ansys.api.dyna.v0 import dynasolver_pb2, dynasolver_pb2_grpc
from ansys.api.dyna.v0 import dynasolver_pb2
import grpc

from . import grpc_tags as tag
from .launcher import * # noqa : F403

#
# Define our own exceptions
Expand Down Expand Up @@ -60,12 +61,46 @@ class DynaSolver:
"""

# logger = None
def __init__(self, hostname, port):
def __init__(self, hostname, port, server_path=""):
"""Create a client instance connected to the host name (or IP address) and port."""
self.hostname = hostname
self.port = port
self.channel = grpc.insecure_channel(hostname + ":" + port)
self.stub = dynasolver_pb2_grpc.DynaSolverCommStub(self.channel)

# start server locally
if (hostname.lower() == "localhost" or hostname == LOCALHOST) and not DynaSolver.grpc_local_server_on():
# LOG.debug("Starting solver server")

if len(server_path) == 0:
server_path = os.getenv("ANSYS_PYDYNA_SOLVER_SERVER_PATH")
if server_path is None:
print("Please set the environment variable for ANSYS_PYDYNA_SOLVER_SERVER_PATH")
return
if os.path.isdir(server_path):
threadserver = ServerThread(1, port=port, ip=hostname, server_path=server_path)
# threadserver.setDaemon(True)
threadserver.start()
waittime = 0
while not DynaSolver.grpc_local_server_on():
sleep(5)
waittime += 5
print(waittime)
if waittime > 60:
print("Failed to start pydyna solver server locally")
break

else:
print("Failed to start pydyna solver server locally,Invalid server path!")

temp = hostname + ":" + str(port)
self.channel = grpc.insecure_channel(temp)
try:
grpc.channel_ready_future(self.channel).result(timeout=5)
except grpc.FutureTimeoutError:
logging.critical("Can not connect to Solver Server")
sys.exit()
logging.info("Connected to Solver Server...")
# self.stub = dynasolver_pb2_grpc.DynaSolverCommStub(self.channel)
self.stub = DynaSolverCommStub(self.channel)
# if DynaSolver.logger is None:
# DynaSolver.logger = logging.getLogger("DynaSolver")
# DynaSolver.logger.setLevel(logging.INFO)
Expand All @@ -78,6 +113,22 @@ def __init__(self, hostname, port):
# self.logger = DynaSolver.logger
self.logger = logging.getLogger("DynaSolver")

@staticmethod
def grpc_local_server_on() -> bool:
"""Check if the server is launched locally.
Returns
-------
bool
``True`` when successful, ``False`` when failed.
"""
channel = grpc.insecure_channel("localhost:5000")
try:
grpc.channel_ready_future(channel).result(timeout=5)
except:
return False
return True

def _argcheck(self, cmd, ngiven, nrequired):
"""Internally used routine for checking command argument counts
when using the generic ``send`` method."""
Expand Down Expand Up @@ -247,12 +298,13 @@ def upload(self, fname):
#
# First packet contains the filename. The rest hold the contents.
#
self.logger.debug("upload: %s" % fname)
# self.logger.debug("upload: %s" % fname)
fsize = 0

def push_packets(fname):
nonlocal fsize
request = dynasolver_pb2.DynaSolverFileData()
# request = dynasolver_pb2.DynaSolverFileData()
request = DynaSolverFileData()
# Only send the base file name, not the whole path!
bfname = os.path.split(fname)[1]
request.b = bytes(bfname, "utf-8")
Expand All @@ -261,7 +313,8 @@ def push_packets(fname):
blocksize = 1000000
n = blocksize
while n == blocksize:
request = dynasolver_pb2.DynaSolverFileData()
# request = dynasolver_pb2.DynaSolverFileData()
request = DynaSolverFileData()
request.b = fp.read(blocksize)
n = len(request.b)
fsize = fsize + n
Expand Down Expand Up @@ -335,7 +388,8 @@ def run(self, args):
Command line to pass to LS-DYNA.
"""
self.logger.debug("run: %s" % args)
request = dynasolver_pb2.DynaSolverRelay()
# request = dynasolver_pb2.DynaSolverRelay()
request = DynaSolverRelay()
request.tag = tag.RUN
request.b = bytes(args, "utf-8")
response = self.stub.send_request(request)
Expand Down Expand Up @@ -369,7 +423,7 @@ def setlc(self, lc, value):
self._check_return(response)
return

def start(self, nproc):
def start(self, nproc, solver_fname=""):
"""Start LS-DYNA.
The program starts and awaits further input. To begin a
Expand All @@ -385,14 +439,36 @@ def start(self, nproc):
Number of cores (MPI ranks) to run.
"""
self.logger.debug("start: %d" % nproc)
request = dynasolver_pb2.DynaSolverStart()
request.exename = b"mppdyna"
# request = dynasolver_pb2.DynaSolverStart()
request = DynaSolverStart()
# request.exename = b"mppdyna"
request.exename = bytes(solver_fname, "utf-8")
request.nproc = nproc
response = self.stub.start_solver(request)
if response.status == tag.RUNNING:
raise RunningError("LSDYNA is already running")
return

def start_locally(self, preset="MPP_DOUBLE", input="", nproc=1, memory=20):
"""Begin execution with the given string as the command-line arguments.
Parameters
----------
args : str
Command line to pass to LS-DYNA.
"""

self.logger.debug("start: %d" % nproc)
request = DynaSolverStartLocal()
request.preset = bytes(preset, "utf-8")
request.input = bytes(input, "utf-8")
request.nproc = nproc
request.memory = memory
response = self.stub.start_solver_locally(request)
# if response.status == tag.RUNNING:
# raise RunningError("LSDYNA is already running")
return

def switch(self, args):
"""Send a "sense switch" to LS-DYNA.
Expand Down
121 changes: 121 additions & 0 deletions src/ansys/dyna/core/solver/launcher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""Module for launching the pydyna solver service locally."""

import socket
import subprocess
import threading

from ansys.dyna.core.pre import LOG

LOCALHOST = "127.0.0.1"
DYNAPRE_DEFAULT_PORT = 50051


def check_ports(port_range, ip="localhost"):
"""Check the state of ports in a port range.
Parameters
----------
port_range :
ip : str, optional
IP address. The default is ``"localhost"``, in which case
``"127.0.0.1"``is used.
"""
ports = {}
for port in port_range:
ports[port] = port_in_use(port, ip)
return ports


def port_in_use(port, host=LOCALHOST):
"""
Determine if a port is in use at a given host.
Parameters
----------
port : int
Port.
host :
Host. The default is ``LOCALHOST``, in which case ``"127.0.0.1"``
is used.
Returns
-------
``True`` when a port is in use at the given host, ``False`` otherwise.
Notes
-----
The port must "bind" the address. Just checking if a socket can be created
is insufficient because it is possible to run into permission
errors like this one:
"An attempt was made to access a socket in a way forbidden by its
access permissions."
"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
try:
sock.bind((host, port))
return False
except:
return True


def launch_grpc(port=DYNAPRE_DEFAULT_PORT, ip=LOCALHOST, server_path=None) -> tuple: # pragma: no cover
"""
Launch the solver service locally in gRPC mode.
Parameters
----------
port : int, optional
Port to launch the solver service on. The default is ``DYNAPRE_DEFAULT_PORT``.
The final port is the first port available after (or including) this
port.
ip : str, optional
IP address. The default is ``LOCALHOST``, in which case ``"127.0.0.1"``
is used.
server_path : string, optional
Path to the solver service. The default is ``None``.
Returns
-------
int
Port number that the gRPC instance started on.
"""
LOG.debug("Starting 'launch_grpc'.")

command = "python kwserver.py"
LOG.debug(f"Starting the solver service with command: {command}")

# env_vars = update_env_vars(add_env_vars, replace_env_vars)
LOG.info(f"Running in {ip}:{port} the following command: '{command}'")

LOG.debug("the solver service starting in background.")
process = subprocess.Popen("python server.py", cwd=server_path, shell=True)
process.wait()
return port


class ServerThread(threading.Thread):
"""Provides server thread properties.
Parameters
----------
threadID :
port :
ip :
server_path :
"""

def __init__(self, threadID, port, ip, server_path):
threading.Thread.__init__(self)
self.threadID = threadID
self.port = port
self.ip = ip
self.server_path = server_path
self.process = None

def run(self):
self.process = launch_grpc(ip=self.ip, port=self.port, server_path=self.server_path)

def termination(self):
self.process.termination()

0 comments on commit fbdbcad

Please sign in to comment.