Skip to content

Commit

Permalink
Consolidate pNBDAC (#35)
Browse files Browse the repository at this point in the history
* consolidate different pNBDAC to a single class

* add more surfaces unit tests

* better handling of buffer_length=0

* udpate ci yml

* fix test for au lattice
  • Loading branch information
daico007 authored Sep 27, 2023
1 parent 8a6b539 commit 1d66074
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 143 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
name: Python Package using Conda
name: CI

on:
push:
branches:
- "main"
pull_request:
branches:
- master
- main
workflow_dispatch:

jobs:
test:
if: github.event.pull_request.draft == false
name: Unit Test on ${{ matrix.os }}, Python ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
Expand Down
165 changes: 26 additions & 139 deletions surface_coatings/chains/nbdac_polymer.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(
self.labels["down"] = backbone["down"]


class SilaneNBDAC(mb.Compound):
class pNBDAC(mb.Compound):
"""A general method to create a NBDAC polymer with varying side chains/terminal groups.
Parameters
Expand All @@ -94,8 +94,11 @@ class SilaneNBDAC(mb.Compound):
Cap the front of the polymer (NBDAC end)
cap_end : bool, optional, default=False
Cap the end of the polymer (Silane end)
silane_buffer : int, optional, default=1
Silane monomer used to buffer at one end of the NBDAC polymer
buffer : str, optional, default=None
Type of buffer to be attached to the end of the pNBDAC.
Available options: None, "alkyl", "ether", "silane"
buffer_length : int, optional, default=1
Length of CH2 monomer to be added to the buffer at one end of the NBDAC polymer
n : int, optional, default=1
Number of repeat for the monomer
port_labels: tuple, optional, default=('up', 'down')
Expand All @@ -111,14 +114,15 @@ def __init__(
monomer,
side_chains=AminoPropyl(),
terminal_groups=Acetaldehyde(),
silane_buffer=1,
buffer=None,
buffer_length=1,
cap_front=True,
cap_end=False,
n=1,
port_labels=("up", "down"),
align=True,
):
super(SilaneNBDAC, self).__init__()
super(pNBDAC, self).__init__()
if monomer:
assert isinstance(monomer, fmNBDAC)
if side_chains and terminal_groups:
Expand All @@ -134,138 +138,27 @@ def __init__(
polymer.build(n=n, add_hydrogens=False)
self.add(polymer, "Polymer")

if silane_buffer:
if buffer:
tail = mb.Compound(name="tail")
tail.add(Silane(), "Silane")
buffer_options = {"alkyl": CH2,
"ether": O,
"silane": Silane}
tail.add(buffer_options.get(buffer.lower())(), "Buffer")
tail.add(CH2(), "CH2_0")

for i in range(silane_buffer):
tail.add(CH2(), f"CH2_{i+1}")
mb.force_overlap(
tail[f"CH2_{i+1}"],
tail[f"CH2_{i+1}"]["down"],
tail[f"CH2_{i}"]["up"],
)

mb.force_overlap(
tail["Silane"], tail["Silane"]["up"], tail[f"CH2_0"]["down"]
)

self.add(tail, "tail")

if align:
polymer_vector = (
polymer[port_labels[1]].anchor.pos
- polymer[port_labels[0]].anchor.pos
)
norm_vector = polymer_vector / np.linalg.norm(polymer_vector)

new_port = mb.Port(
anchor=polymer[port_labels[0]].anchor,
orientation=norm_vector,
separation=0.07,
)

polymer[port_labels[0]].update_orientation(
orientation=norm_vector
)

mb.force_overlap(
tail, tail[f"CH2_{i+1}"]["up"], polymer[port_labels[0]]
)

self.labels["up"] = self["Polymer"][port_labels[1]]
self.labels["down"] = self["tail"]["Silane"]["down"]
else:
self.labels["up"] = self["Polymer"]["up"]
self.labels["down"] = self["Polymer"]["down"]

if cap_front:
front_cap = H()
self.add(front_cap, "front_cap")
mb.force_overlap(
move_this=front_cap,
from_positions=front_cap["up"],
to_positions=self["up"],
)
if cap_end:
end_cap = H()
self.add(end_cap, "end_cap")
mb.force_overlap(
move_this=end_cap,
from_positions=end_cap["up"],
to_positions=self["down"],
)

class EtherNBDAC(mb.Compound):
"""A general method to create a NBDAC polymer with varying side chains/terminal groups.
Option to add an ether cap (to connect to a surface)
Parameters
----------
side_chains : mb.Compound or list of Compounds (len 2)
Side chains attached to NBDAC monomer
terminal_groups: mb.Compound or list of Compounds (len 2)
Terminal groups which will be matched with side chains
cap_front : bool, optional, default=True
Cap the front of the polymer (NBDAC end)
cap_end : bool, optional, default=False
Cap the end of the polymer (Silane end)
ether_buffer : int, optional, default=1
Ether used to buffer at one end of the NBDAC polymer
n : int, optional, default=1
Number of repeat for the monomer
port_labels: tuple, optional, default=('up', 'down')
The list of ports of the monomers. The Silane will connect with the first port
and the last port will be capped by a Hydrogen
algin : bool, optional, default=True
If True, align the port connected to the silane buffer with the rest of the polymer.
The goal is to create a straight polymer when grafted on a surface.
"""

def __init__(
self,
monomer,
side_chains=AminoPropyl(),
terminal_groups=Acetaldehyde(),
ether_buffer=1,
cap_front=True,
cap_end=False,
n=1,
port_labels=("up", "down"),
align=True,
):
super(EtherNBDAC, self).__init__()
if monomer:
assert isinstance(monomer, fmNBDAC)
if side_chains and terminal_groups:
warnings.warn(
"Both monomer and (side_chains, terminal_groups) are provided,"
"only monomer will be used to construct the polymer."
"Please refer to docstring for more information."
)
else:
monomer = fmNBDAC(side_chains, terminal_groups)

polymer = Polymer(monomers=[monomer])
polymer.build(n=n, add_hydrogens=False)
self.add(polymer, "Polymer")

if ether_buffer:
tail = mb.Compound(name="tail")
tail.add(O(), "O_init")
tail.add(CH2(), "CH2_0")

for i in range(ether_buffer):
tail.add(CH2(), f"CH2_{i+1}")
mb.force_overlap(
tail[f"CH2_{i+1}"],
tail[f"CH2_{i+1}"]["down"],
tail[f"CH2_{i}"]["up"],
)
if buffer_length >= 1:
for i in range(buffer_length):
tail.add(CH2(), f"CH2_{i+1}")
mb.force_overlap(
tail[f"CH2_{i+1}"],
tail[f"CH2_{i+1}"]["down"],
tail[f"CH2_{i}"]["up"],
)
else:
i = -1

mb.force_overlap(
tail["O_init"], tail["O_init"]["up"], tail[f"CH2_0"]["down"]
tail["Buffer"], tail["Buffer"]["up"], tail[f"CH2_0"]["down"]
)

self.add(tail, "tail")
Expand All @@ -277,12 +170,6 @@ def __init__(
)
norm_vector = polymer_vector / np.linalg.norm(polymer_vector)

new_port = mb.Port(
anchor=polymer[port_labels[0]].anchor,
orientation=norm_vector,
separation=0.07,
)

polymer[port_labels[0]].update_orientation(
orientation=norm_vector
)
Expand All @@ -292,7 +179,7 @@ def __init__(
)

self.labels["up"] = self["Polymer"][port_labels[1]]
self.labels["down"] = self["tail"]["O_init"]["down"]
self.labels["down"] = self["tail"]["Buffer"]["down"]
else:
self.labels["up"] = self["Polymer"]["up"]
self.labels["down"] = self["Polymer"]["down"]
Expand Down
3 changes: 2 additions & 1 deletion surface_coatings/surfaces/au_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ def __init__(self, x=5, y=5, n_layers=3):

self.add(au_sheet)

self.xyz -= np.min(self.xyz, axis=0)
self.xyz -= np.min(self.xyz, axis=0)

self.xyz -= np.min(self.xyz, axis=0)
self.periodicity = (True, True, True)
4 changes: 3 additions & 1 deletion surface_coatings/surfaces/graphene_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ def __init__(self, x=5, y=5, n_layers=3):
self.add(graphene)
self.xyz -= np.min(self.xyz, axis=0)

self.xyz -= np.min(self.xyz, axis=0)
self.xyz -= np.min(self.xyz, axis=0)

self.periodicity = (True, True, False)
11 changes: 11 additions & 0 deletions surface_coatings/tests/test_surfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
SilicaInterface,
SilicaInterfaceCarve,
SiliconInterface,
GrapheneSheet,
AuLattice,

)


Expand All @@ -19,3 +22,11 @@ def test_silica_interface_carve(self):
def test_silica_interface(self):
silica_surface = SilicaInterface()
assert silica_surface.periodicity == (True, True, False)

def test_graphene_interface(self):
graphene_sheet = GrapheneSheet()
assert graphene_sheet.periodicity == (True, True, False)

def test_au_interface(self):
au_interface = AuLattice()
assert au_interface.periodicity == (True, True, True)

0 comments on commit 1d66074

Please sign in to comment.