<commit_before># -*- coding: utf-8 -*-
"""
=============================================================================
Generate defects in structure data (:mod:`sknano.nanogen._defect_generators`)
=============================================================================

.. currentmodule:: sknano.nanogen._defect_generators

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

from collections import OrderedDict
import os

import numpy as np

from ..structure_io import DATAReader, DATAWriter, XYZWriter, \
    XYZ2DATAConverter, StructureFormatError, supported_structure_formats
from ..structure_io.atoms import LAMMPSAtoms as Atoms

xyz_tuple = ('x', 'y', 'z')
vac_type_cluster_size_map = {'double': 2, 'triple': 3}

__all__ = ['DefectGenerator', 'CrossLinkedDefectGenerator',
           'StoneWalesDefectGenerator', 'VacancyGenerator']


class DefectGenerator(object):
    """Base class for generating defects in structure data.

    Parameters
    ----------
    fname : str
        structure data filename
    outpath : str, optional
        Output path for structure data file.
    structure_format : {None, str}, optional
        chemical file format of saved structure data.
        If `None`, then guess based on `fname` file extension.
        Otherwise, must be one of:

            - `xyz`
            - `data`

    verbose : bool, optional
        Verbose output

    """
    def __init__(self, fname=str, outpath=None, structure_format=None,
                 verbose=False):

        if fname.endswith(supported_structure_formats) and \
                structure_format is None:
            for ext in supported_structure_formats:
                if fname.endswith(ext):
                    structure_format = ext
                    break
        else:
            if (not fname.endswith(supported_structure_formats) and
                    structure_format is None) or \
                    (structure_format is not None and
                        structure_format not in supported_structure_formats):
                raise StructureFormatError(
                    '{} is not a supported structure format'.format(
                        structure_format))

        self._fname = fname
        self._outpath = outpath
        self._structure_format = structure_format
        self._verbose = verbose

        # parse structure data
        if self._structure_format == 'data':
            self._structure_data = DATAReader(fname)
        elif self._structure_format == 'xyz':
            self._structure_data = \
                XYZ2DATAConverter(fname).convert(return_reader=True)

        self._atoms = self._structure_data.atoms
        self._atom_ids = self._atoms.atom_ids
        self._atom_coords = self._atoms.get_coords(as_dict=True)

    @property
    def atoms(self):
        return self._atoms

    @property
    def atom_ids(self):
        return self._atom_ids

    @property
    def atom_coords(self):
        return self._atom_coords


class CrossLinkedDefectGenerator(DefectGenerator):
    pass


class StoneWalesDefectGenerator(DefectGenerator):
    pass


class VacancyGenerator(DefectGenerator):
    """Class for generating vacancies in structure data.

    Parameters
    ----------
    fname : str
        structure data filename
    outpath : str, optional
        Output path for structure data file.
    structure_format : {None, str}, optional
        chemical file format of saved structure data.
        If `None`, then guess based on `fname` file extension.
        Otherwise, must be one of:

            - `xyz`
            - `data`

    verbose : bool, optional
        Verbose output

    """
    def __init__(self, fname=str, outpath=None, structure_format=None,
                 verbose=False):
        super(VacancyGenerator, self).__init__(
            fname=fname, outpath=outpath, structure_format=structure_format,
            verbose=verbose)

        self._Nvacs = 0
        self._Nvac_clusters = 0
        self._Nvac_sites = 0

        self._vac_bounds = OrderedDict(zip(xyz_tuple, 3 * [2 * [None]]))

        self._vac_ids = np.empty(0, dtype=int)
        self._vac_type = 'single'
        self._cluster_size = 1

        self._vmd_selection_radius = np.sqrt(10.5)
        self._show_vmd_selection_cmd = True

    @property
    def Nvacs(self):
        return self._Nvacs

    @Nvacs.setter
    def Nvacs(self, value=int):
        self._Nvacs = value

    @property
    def Nvac_clusters(self):
        return self._Nvac_clusters

    @Nvac_clusters.setter
    def Nvac_clusters(self, value=int):<commit_msg>Adding code for StoneWalesDefectGenerator class<commit_after># -*- coding: utf-8 -*-
"""
=============================================================================
Generate defects in structure data (:mod:`sknano.nanogen._defect_generators`)
=============================================================================

.. currentmodule:: sknano.nanogen._defect_generators

"""
from __future__ import absolute_import, division, print_function
__docformat__ = 'restructuredtext en'

from collections import OrderedDict
import os

import numpy as np

from ..structure_io import DATAReader, DATAWriter, XYZWriter, \
    XYZ2DATAConverter, StructureFormatError, supported_structure_formats
from ..structure_io.atoms import LAMMPSAtoms as Atoms

xyz_tuple = ('x', 'y', 'z')
vac_type_cluster_size_map = {'double': 2, 'triple': 3}

__all__ = ['DefectGenerator', 'CrossLinkedDefectGenerator',
           'StoneWalesDefectGenerator', 'VacancyGenerator']


class DefectGenerator(object):
    """Base class for generating defects in structure data.

    Parameters
    ----------
    fname : str
        structure data filename
    outpath : str, optional
        Output path for structure data file.
    structure_format : {None, str}, optional
        chemical file format of saved structure data.
        If `None`, then guess based on `fname` file extension.
        Otherwise, must be one of:

            - `xyz`
            - `data`

    verbose : bool, optional
        Verbose output

    """
    def __init__(self, fname=str, outpath=None, structure_format=None,
                 verbose=False):

        if fname.endswith(supported_structure_formats) and \
                structure_format is None:
            for ext in supported_structure_formats:
                if fname.endswith(ext):
                    structure_format = ext
                    break
        else:
            if (not fname.endswith(supported_structure_formats) and
                    structure_format is None) or \
                    (structure_format is not None and
                        structure_format not in supported_structure_formats):
                raise StructureFormatError(
                    '{} is not a supported structure format'.format(
                        structure_format))

        self._fname = fname
        self._outpath = outpath
        self._structure_format = structure_format
        self._verbose = verbose

        # parse structure data
        if self._structure_format == 'data':
            self._structure_data = DATAReader(fname)
        elif self._structure_format == 'xyz':
            self._structure_data = \
                XYZ2DATAConverter(fname).convert(return_reader=True)

        self._atoms = self._structure_data.atoms
        self._atom_ids = self._atoms.atom_ids
        self._atom_coords = self._atoms.get_coords(as_dict=True)

    @property
    def atoms(self):
        return self._atoms

    @property
    def atom_ids(self):
        return self._atom_ids

    @property
    def atom_coords(self):
        return self._atom_coords


class CrossLinkedDefectGenerator(DefectGenerator):
    pass


class StoneWalesDefectGenerator(DefectGenerator):
    """Class for generating Stone-Wales defects in structure data.

    Parameters
    ----------
    fname : str
        structure data filename
    outpath : str, optional
        Output path for structure data file.
    structure_format : {None, str}, optional
        chemical file format of saved structure data.
        If `None`, then guess based on `fname` file extension.
        Otherwise, must be one of:

            - `xyz`
            - `data`

    verbose : bool, optional
        Verbose output

    """
    def __init__(self, fname=str, outpath=None, structure_format=None,
                 verbose=False):
        super(StoneWalesDefectGenerator, self).__init__(
            fname=fname, outpath=outpath, structure_format=structure_format,
            verbose=verbose)

        self._defect_bounds = OrderedDict(zip(xyz_tuple, 3 * [2 * [None]]))

        self._vmd_selection_radius = np.sqrt(10.5)
        self._show_vmd_selection_cmd = True


class VacancyGenerator(DefectGenerator):
    """Class for generating vacancies in structure data.

    Parameters
    ----------
    fname : str
        structure data filename
    outpath : str, optional
        Output path for structure data file.
    structure_format : {None, str}, optional
        chemical file format of saved structure data.
        If `None`, then guess based on `fname` file extension.
        Otherwise, must be one of:

            - `xyz`
            - `data`

    verbose : bool, optional
        Verbose output

    """
    def __init__(self, fname=str, outpath=None, structure_format=None,
                 verbose=False):
        super(VacancyGenerator, self).__init__(
            fname=fname, outpath=outpath, structure_format=structure_format,
            verbose=verbose)

        self._Nvacs = 0
        self._Nvac_clusters = 0
        self._Nvac_sites = 0

        self._vac_bounds = OrderedDict(zip(xyz_tuple, 3 * [2 * [None]]))

        self._vac_ids = np.empty(0, dtype=int)
        self._vac_type = 'single'
        self._cluster_size = 1

        self._vmd_selection_radius = np.sqrt(10.5)
        self._show_vmd_selection_cmd = True

    @property
    def Nvacs(self):
        return self._Nvacs

    @Nvacs.setter
    def Nvacs(self, value=int):
        self._Nvacs = value

    @property
    def Nvac_clusters(self):
        return self._Nvac_clusters

    @Nvac_clusters.setter
    def Nvac_clusters(self, value=int):
{'fraction_non_alphanumeric': 0.1120647615332098, 'fraction_numerical': 0.0034136350336486884, 'mean_word_length': 2.423706176961603, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '804738', 'n_tokens_mistral': 2947, 'n_tokens_neox': 2748, 'n_words': 722}