Skip to content

Commit

Permalink
Merge pull request #1427 from ghutchis/add-cjson-connect-python
Browse files Browse the repository at this point in the history
Add some additional Python classes including cjson and connect
  • Loading branch information
ghutchis committed Dec 29, 2023
2 parents 1fdede3 + cec6bad commit 52aaf9f
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 26 deletions.
4 changes: 3 additions & 1 deletion python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,9 @@ if (NOT WIN32)
INSTALL_RPATH ${_rpath_value})
endif()

install(FILES avogadro/__init__.py COMPONENT python DESTINATION "${_python_module_install_dir}")
# Install the python files.
FILE(GLOB PY_SRCS "avogadro/*.py")
install(FILES ${PY_SRCS} COMPONENT python DESTINATION "${_python_module_install_dir}")

# Set the output directory so the python modules can be used from the build
# tree.
Expand Down
2 changes: 2 additions & 0 deletions python/avogadro/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from . import cjson
from . import connect
from . import core
from . import io
70 changes: 45 additions & 25 deletions python/avogadro/cjson.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
"""
/******************************************************************************
This source file is part of the Avogadro project.
This source code is released under the New BSD License, (the "License").
This source code is released under the 3-clause BSD License, (the "License").
******************************************************************************/
"""
import json
class Cjson:


class cjson:
"""
This Class is intended to read Cjson files
with python libraries and perform certain
methods on files and convert them back to Cjson
files as required
This class is intended to read and write cjson (chemical json) files
and help manipulate them (e.g., change coordinates, elements, etc.)
The cjson format is a JSON format for chemical information. It is
intended to be a common exchange and storage format for chemical
information that is both human and machine readable. It is intended
to be easily extended to support new features and data types.
More information and the schema can be found at:
https://github.com/OpenChemistry/chemicaljson
"""

def __init__(self):
pass

def __from_cjson(self, filePath):
'''Use to read CJson formats by converting them to python dictionaries'''
with open(filePath, 'r') as cjsonFile:
"""Use to read cjson formats by converting them to python dictionaries"""
with open(filePath, "r") as cjsonFile:
py_dict_data = json.load(cjsonFile)
return py_dict_data

def __to_cjson(self, cjson_dict_file):
'''It converts python dictionaries to CJson format'''
"""It converts python dictionaries to cjson format"""
cjsonData = json.dumps(cjson_dict_file, indent=4)
return (cjsonData)
def get_atoms_coords(self,filePath):
return cjsonData

def get_atoms_coords(self, filePath):
"""
It helps to get the co-ordinates of individual elements/atoms in the format
[
Expand All @@ -36,44 +48,52 @@ def get_atoms_coords(self,filePath):
data = self.__from_cjson(filePath)
coords = data["atoms"]["coords"]["3d"]
elements = data["atoms"]["elements"]["number"]
element_coords = [(*coords[i*3:(i+1)*3], elements[i]) for i in range(0, int(len(coords) / 3))]
cjson_dict = {"element-coordinates" :element_coords}
element_coords = [
(*coords[i * 3 : (i + 1) * 3], elements[i])
for i in range(0, int(len(coords) / 3))
]
cjson_dict = {"element-coordinates": element_coords}
return self.__to_cjson(cjson_dict)

def get_elements(self, filePath):
'''
"""
returns all the elements present in cjson file
'''
"""
data = self.__from_cjson(filePath)
elements = data["atoms"]["elements"]["number"]
return elements
def get_coordinates(self,filePath):
'''

def get_coordinates(self, filePath):
"""
returns the coordinate array
'''
"""
data = self.__from_cjson(filePath)
coords = data["atoms"]["coords"]["3d"]
return coords

def set_atoms_coordinates(self, filePath, coords_array):
'''
"""
it updates the coordinates array in cjson file
'''
"""
data = self.__from_cjson(filePath)
data["atoms"]["coords"]["3d"] = coords_array
return self.__to_cjson(data)

def set_elements(self, filePath, elements_array):
'''
"""
It sets all the elements present in the cjson file
where elements are set/recognized by their atomic numbers
'''
"""
data = self.__from_cjson(filePath)
data["atoms"]["elements"]["number"] = elements_array
return self.__to_cjson(data)

def set_coordinates(self, filePath, coords_array):
'''
"""
It helps to set all coordinates of the
cjson file where coordinates of all elements
can be changed by an input array of coords_array
'''
"""
data = self.__from_cjson(filePath)
data["atoms"]["coords"]["3d"] = coords_array
return self.__to_cjson(data)
return self.__to_cjson(data)
99 changes: 99 additions & 0 deletions python/avogadro/connect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
"""
/******************************************************************************
This source file is part of the Avogadro project.
This source code is released under the 3-clause BSD License, (the "License").
******************************************************************************/
"""

import json
import os
import socket
import struct
import sys
import tempfile


class connect:
"""
Send JSON-RPC requests to Avogadro through a named pipe.
This class is intended to be used by external scripts that are
run on the same machine as Avogadro.
The named pipe is created by Avogadro and is named "avogadro".
If it does not exist, Avogadro is not running.
"""

def __init__(self, name="avogadro"):
"""
Connect to the local named pipe
:param name: The name of the named pipe.
"""
# create socket and connect
try:
if os.name == "nt":
self.sock = open("//./pipe/" + name, "w+b", 0)
else:
self.sock.connect(tempfile.gettempdir() + "/" + name)
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)

except Exception as exception:
print("error while connecting: " + str(exception))
print("Is Avogadro running?")

def __json(self, method, params={}):
"""
Send a JSON-RPC request to the named pipe.
:param method: The JSON-RPC request method.
Send a message to the named pipe
:param file: file corresponding to method.
"""
if method == "receive_message":
size = 1024
if os.name == "nt":
packet = self.sock.read(size)
else:
packet = self.sock.recv(size)

try:
return json.loads(str(packet[4:]))
except Exception as exception:
print("error: " + str(exception))
return {}
else:
msg = {
"jsonrpc": "2.0",
"id": 0,
"method": method,
"params": params,
}
json_msg = json.dumps(msg)
size = len(json_msg)
header = struct.pack(">I", size)
packet = header + json_msg.encode("ascii")
if os.name == "nt":
self.sock.write(packet)
self.sock.seek(0)
else:
self.sock.send(packet)

def open_file(self, file):
"""Opens file"""
# param: file is filename input by the user in string
method = "openFile"
params = {"filename": file}
self.__json(method, params)
self.__json("receive_message")

def save_graphic(self, file):
"""Save Graphic"""
method = "saveGraphic"
params = {"filename": file}
self.__json(method, params)
self.__json("receive_message")

def close(self):
"""Close the socket to the named pipe"""
self.sock.close()
3 changes: 3 additions & 0 deletions python/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <avogadro/quantumio/mopacaux.h>
#include <avogadro/quantumio/nwchemjson.h>
#include <avogadro/quantumio/nwchemlog.h>
#include <avogadro/quantumio/orca.h>

namespace py = pybind11;

Expand Down Expand Up @@ -68,12 +69,14 @@ PYBIND11_MODULE(io, m)

/// Add the quantum IO formats, we should probably move them over soon, but
/// get things working for now...
Io::FileFormatManager::registerFormat(new GAMESSUSOutput);
Io::FileFormatManager::registerFormat(new GaussianFchk);
Io::FileFormatManager::registerFormat(new GaussianCube);
Io::FileFormatManager::registerFormat(new MoldenFile);
Io::FileFormatManager::registerFormat(new MopacAux);
Io::FileFormatManager::registerFormat(new NWChemJson);
Io::FileFormatManager::registerFormat(new NWChemLog);
Io::FileFormatManager::registerFormat(new ORCAOutput);

/// This class uses a singleton pattern, make it accessible through Python.
py::class_<ffm>(m, "FileFormatManager")
Expand Down

0 comments on commit 52aaf9f

Please sign in to comment.