#!/usr/bin/env python
from __future__ import print_function
from __future__ import division
from past.utils import old_div
#
#
# Author: Markus Stabrin 2019 (markus.stabrin@mpi-dortmund.mpg.de)
# Author: Fabian Schoenfeld 2019 (fabian.schoenfeld@mpi-dortmund.mpg.de)
# Author: Thorsten Wagner 2019 (thorsten.wagner@mpi-dortmund.mpg.de)
# Author: Toshio Moriya 2015-2019 (toshio.moriya@kek.jp)
#
# Copyright (c) 2015-2019 Max Planck Institute of Molecular Physiology
#
# This software is issued under a joint BSD/GNU license. You may use the
# source code in this file under either license. However, note that the
# complete SPHIRE and EMAN2 software packages have some GPL dependencies,
# so you are responsible for compliance with the licenses of these packages
# if you opt to use BSD licensing. The warranty disclaimer below holds
# in either instance.
#
# This complete copyright notice must be included in any revised version of the
# source code. Additional authorship citations may be added, but existing
# author citations must be preserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# ========================================================================================
# NOTE: 2015/10/19 Toshio Moriya
# Now the script also stores the extract information in the stack header
#
# NOTE: 2015/10/19 Toshio Moriya
# The script stores the RELION's particle ID in the ptcl_source_coord_id header entry.
# This ID is generated by RELION when it extract particles using the original box file (before particle screening)
# If you run sxwindow.py using the box files generated by this script, ptcl_source_coord_id will be reassigned,
# which is different from RELION's particle ID because it is after particle screening
#
# ========================================================================================

import EMAN2_cppwrap
import EMAN2db
import numpy
import operator
import optparse
import os
import subprocess
from ..libpy import sp_global_def
from ..libpy import sp_morphology
from ..libpy import sp_pixel_error
from ..libpy import sp_statistics
from ..libpy import sp_utilities
import sys
from builtins import range
from past.builtins import cmp


# ========================================================================================
# Helper Functions
# ========================================================================================
# ----------------------------------------------------------------------------------------
# Generate command line
# ----------------------------------------------------------------------------------------


def get_cmd_line():
    cmd_line = ""
    for arg in sys.argv:
        cmd_line += arg + "  "
    cmd_line = "Shell line command: " + cmd_line
    return cmd_line


# ----------------------------------------------------------------------------------------
# Create relative path of path p2 to p1
# ----------------------------------------------------------------------------------------


def makerelpath(p1, p2):
    """Takes a pair of paths /a/b/c/d and /a/b/e/f/g and returns a relative path to b from a, ../../e/f/g"""

    p1s = [i for i in os.path.realpath(p1).split("/") if len(i) > 0]
    p2s = [i for i in os.path.realpath(p2).split("/") if len(i) > 0]

    for dv in range(min(len(p1s), len(p2s))):
        if p1s[dv] != p2s[dv]:
            break
    else:
        dv += 1

    p1s = p1s[dv:]
    p2s = p2s[dv:]

    return "../" * len(p1s) + "/".join(p2s)


def estimate_angle(coords_a, coords_b):
    """
	Estimates the angle given by a line between two  boxes.
	:param coords_a: First coordinate pair
	:param coords_b: Second coordinate pair
	:return: Angle from positive x axis twoards the positiv y axis.
	"""
    delta_x = coords_b[0] - coords_a[0]
    delta_y = coords_b[1] - coords_a[1]
    angle = old_div(-1 * numpy.arctan2(delta_y, delta_x) * 180, numpy.pi)

    return angle


# ========================================================================================
# Main function
# ========================================================================================


def run():
    # Parse command argument
    arglist = []
    for arg in sys.argv:
        arglist.append(arg)

    progname = os.path.basename(arglist[0])
    usage = (
        progname
        + " input_star_file output_directory --relion_project_dir=DIR_PATH --star_section=SECTION_STRING --outputs_root=ROOT_NAME_STRING --box_size=BOX_SIZE --do_not_create_stack"
    )
    parser = optparse.OptionParser(usage, version=sp_global_def.SPARXVERSION)

    parser.add_option(
        "--relion_project_dir",
        type="string",
        default=None,
        help="RELION project directory: Path to RELION project directory associated with the RELION STAR file. By default, the program assume the current directory is the RELION project directory. (default none)",
    )
    parser.add_option(
        "--star_section",
        type="string",
        default="data_particles",
        help="Section title in STAR file: The section title in the RELION star file where the data should be extracted. (default data_particles)",
    )
    parser.add_option(
        "--outputs_root",
        type="string",
        default="sphire",
        help="Root name of outputs: Specify the root name of all outputs. It cannot be empty string or only white spaces. (default sphire)",
    )
    parser.add_option(
        "--box_size",
        type=int,
        default=0,
        help="Box size: Box size for particle extraction. It also controls the saved coordinates file format. If the given value is > 0, store the eman1 format. coordinate file. The coordinates of eman1 format is particle box corner associated with this box size. The coordinates of sphire format is particle center. By default, use sphire format. (default 0)",
    )
    parser.add_option(
        "--do_not_create_stack",
        action="store_true",
        default=False,
        help="Create virtual stacks: Create per-micrograph virtual stacks without the actual particle meta information in BDB format. By default, the program does generate the stack of particle meta information (default False)",
    )
    parser.add_option(
        "--negative_stain",
        action="store_true",
        default=False,
        help="Create negative stain CTF entry (default False)",
    )

    (options, args) = parser.parse_args(arglist[1:])

    # ------------------------------------------------------------------------------------
    # Check validity of input arguments and options
    # ------------------------------------------------------------------------------------
    if len(args) != 2:
        sp_global_def.sxprint("Usage: " + usage)
        sp_global_def.sxprint("Please run '" + progname + " -h' for detailed options")
        sp_global_def.ERROR(
            "Missing paths to input STAR file and output directory. Please see usage information above"
        )
        return

    sp_global_def.sxprint("# ")
    sp_global_def.sxprint("# %s" % get_cmd_line())
    sp_global_def.sxprint("# ")

    # Rename arguments and options for readability
    file_path_relion_star = args[0]
    dir_path_work = args[1]

    dir_path_relion_project = options.relion_project_dir
    str_relion_start_section = options.star_section

    outputs_root = options.outputs_root.strip()
    box_size = options.box_size
    is_enable_create_stack = bool(not options.do_not_create_stack)

    if not os.path.exists(file_path_relion_star):
        sp_global_def.ERROR(
            "Input RELION STAR file '" + file_path_relion_star + "' is not found."
        )
        return

    if os.path.exists(dir_path_work):
        sp_global_def.ERROR(
            "Output directory '"
            + dir_path_work
            + "' already exists. Please delete it or use a different output directory"
        )
        return

    if dir_path_relion_project is not None:
        if not os.path.exists(dir_path_relion_project):
            sp_global_def.ERROR(
                "Specified RELION project directory '"
                + dir_path_relion_project
                + "' does not exist."
            )
            return

    # ------------------------------------------------------------------------------------
    # Constants
    # ------------------------------------------------------------------------------------
    # Initialise dictionary for RELION params file related items
    idx_col = 0
    idx_title = 1

    relion_dict = {}
    relion_dict["_rlnMicrographName"] = [
        -1,
        "#     Micrograph Name      := %2d (%s)",
    ]  # Micrograph, CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnDefocusU"] = [
        -1,
        "#     Defocus U            := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnDefocusV"] = [
        -1,
        "#     Defocus V            := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnDefocusAngle"] = [
        -1,
        "#     Defocus Angle        := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnAmplitudeContrast"] = [
        -1,
        "#     Amp. Contrast        := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnPhaseShift"] = [
        -1,
        "#     Phase shift          := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d    # For Volta Phase Support
    relion_dict["_rlnVoltage"] = [
        -1,
        "#     Acc. Vol.            := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnSphericalAberration"] = [
        -1,
        "#     Cs                   := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnMagnification"] = [
        -1,
        "#     Mag.                 := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnDetectorPixelSize"] = [
        -1,
        "#     Det. Pix. Size       := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnCtfFigureOfMerit"] = [
        -1,
        "#     CTF Fig. of Merit    := %2d (%s)",
    ]  # CTF, Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnCtfMaxResolution"] = [
        -1,
        "#     CTF Max Resolution   := %2d (%s)",
    ]  # CTF,
    relion_dict["_rlnCtfImage"] = [-1, "#     CTF Image            := %2d (%s)"]  # CTF
    relion_dict["_rlnImageName"] = [
        -1,
        "#     Particle Source      := %2d (%s)",
    ]  # Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnCoordinateX"] = [
        -1,
        "#     X Coordinate         := %2d (%s)",
    ]  # Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnCoordinateY"] = [
        -1,
        "#     Y Coordinate         := %2d (%s)",
    ]  # Window, Class2d, Class3d, Refine3d
    relion_dict["_rlnOriginX"] = [
        -1,
        "#     X Translation        := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnOriginY"] = [
        -1,
        "#     Y Translation        := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnAngleRot"] = [
        -1,
        "#     Rotation             := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnAngleTilt"] = [
        -1,
        "#     Tilt                 := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnAnglePsi"] = [
        -1,
        "#     Psi                  := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnMaxValueProbDistribution"] = [
        -1,
        "#     Max Probability      := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnNormCorrection"] = [
        -1,
        "#     Norm Correction      := %2d (%s)",
    ]  # Class2d, Class3d, Refine3d
    relion_dict["_rlnRandomSubset"] = [
        -1,
        "#     Random Subset        := %2d (%s)",
    ]  # Refine3d
    relion_dict["_rlnHelicalTubeID"] = [
        -1,
        "#     Helical Tube ID      := %2d (%s)",
    ]  # Helical    # For Helical Reconstruction Support
    relion_dict["_rlnAngleTiltPrior"] = [
        -1,
        "#     Ang. Tilt Prior      := %2d (%s)",
    ]  # Helical    # For Helical Reconstruction Support
    relion_dict["_rlnAnglePsiPrior"] = [
        -1,
        "#     Ang. Psi Prior       := %2d (%s)",
    ]  # Helical    # For Helical Reconstruction Support
    relion_dict["_rlnHelicalTrackLength"] = [
        -1,
        "#     Helical Track Len.   := %2d (%s)",
    ]  # Helical    # For Helical Reconstruction Support
    relion_dict["_rlnAnglePsiFlipRatio"] = [
        -1,
        "#     Ang. Psi. Flip Ratio := %2d (%s)",
    ]  # Helical    # For Helical Reconstruction Support

    idx_relion_process = 0
    idx_is_category_found = 1
    idx_required_key_list = 2
    idx_denpended_key_list = 3
    idx_optional_key_list = 4

    relion_category_dict = {}
    relion_category_dict["mic"] = ["Micrographs", True, ["_rlnMicrographName"], [], []]
    relion_category_dict["ctf"] = [
        "CTF Estimation",
        True,
        [
            "_rlnDefocusU",
            "_rlnDefocusV",
            "_rlnDefocusAngle",
            "_rlnAmplitudeContrast",
            "_rlnVoltage",
            "_rlnSphericalAberration",
            "_rlnMagnification",
        ],
        ["mic"],
        [
            "_rlnPhaseShift",
            "_rlnCtfFigureOfMerit",
            "_rlnCtfMaxResolution",
            "_rlnCtfImage",
        ],
    ]
    relion_category_dict["window"] = [
        "Particle Extraction",
        True,
        ["_rlnImageName", "_rlnCoordinateX", "_rlnCoordinateY"],
        ["mic"],
        [],
    ]
    relion_category_dict["proj3d"] = [
        "Alignment Parameters",
        True,
        [
            "_rlnOriginX",
            "_rlnOriginY",
            "_rlnAngleRot",
            "_rlnAngleTilt",
            "_rlnAnglePsi",
            "_rlnMaxValueProbDistribution",
            "_rlnNormCorrection",
        ],
        [],
        [],
    ]
    relion_category_dict["chunk"] = [
        "Random Subset",
        True,
        ["_rlnRandomSubset"],
        [],
        [],
    ]
    relion_category_dict["helical"] = [
        "Helical Tube Extraction",
        True,
        ["_rlnHelicalTubeID", "_rlnHelicalTrackLength"],
        ["mic", "window"],
        [],
    ]

    # SPHIRE params output files & directories related
    file_name_sphire_micrographs = "{}_micrographs.txt".format(outputs_root)
    file_name_sphire_cter_partres = "{}_cter_partres.txt".format(outputs_root)
    file_name_sphire_cter_per_particle = "{}_ctf_per_particle.txt".format(outputs_root)
    # name_pattern_sphire_stack_chunk = '{}_stack_chunk*.txt'.format(outputs_root)

    dir_name_coordinates = "Coordinates"
    dir_name_rebox = "Rebox"
    if is_enable_create_stack:
        dir_name_local_stacks = "Particles"

    # For particle source (window) parameters file format
    i_enum = -1
    i_enum += 1
    idx_ptcl_source_coord_id = i_enum
    i_enum += 1
    idx_ptcl_source_coord_x = i_enum
    i_enum += 1
    idx_ptcl_source_coord_y = i_enum
    i_enum += 1
    idx_ptcl_source_resample_ratio = i_enum
    i_enum += 1
    idx_ptcl_source_filament_id = i_enum
    i_enum += 1
    n_idx_ptcl_source = i_enum

    # For CTER parameters file format
    i_enum = -1
    i_enum += 1
    idx_cter_def = i_enum  # defocus [um]; index must be same as CTF object format
    i_enum += 1
    idx_cter_cs = i_enum  # Cs [mm]; index must be same as CTF object format
    i_enum += 1
    idx_cter_vol = i_enum  # voltage[kV]; index must be same as CTF object format
    i_enum += 1
    idx_cter_apix = i_enum  # pixel size [A]; index must be same as CTF object format
    i_enum += 1
    idx_cter_bfactor = i_enum  # B-factor [A^2]; index must be same as CTF object format
    i_enum += 1
    idx_cter_total_ac = (
        i_enum
    )  # total amplitude contrast [%]; index must be same as CTF object format
    i_enum += 1
    idx_cter_astig_amp = (
        i_enum
    )  # astigmatism amplitude [um]; index must be same as CTF object format
    i_enum += 1
    idx_cter_astig_ang = (
        i_enum
    )  # astigmatism angle [degrees]; index must be same as CTF object format
    i_enum += 1
    idx_cter_sd_def = i_enum  # std dev of defocus [um]
    i_enum += 1
    idx_cter_sd_total_ac = i_enum  # std dev of total amplitude contrast [%]
    i_enum += 1
    idx_cter_sd_astig_amp = i_enum  # std dev of ast amp [A]
    i_enum += 1
    idx_cter_sd_astig_ang = i_enum  # std dev of ast angle [degrees]
    i_enum += 1
    idx_cter_cv_def = i_enum  # coefficient of variation of defocus [%]
    i_enum += 1
    idx_cter_cv_astig_amp = i_enum  # coefficient of variation of ast amp [%]
    i_enum += 1
    idx_cter_error_def = (
        i_enum
    )  # frequency at which signal drops by 50% due to estimated error of defocus alone [1/A]
    i_enum += 1
    idx_cter_error_astig = (
        i_enum
    )  # frequency at which signal drops by 50% due to estimated error of defocus and astigmatism [1/A]
    i_enum += 1
    idx_cter_error_ctf = i_enum  # limit frequency by CTF error [1/A]
    i_enum += 1
    idx_cter_max_freq = (
        i_enum
    )  # visual-impression-based maximum frequency limit [A] (e.g. max frequency of RELION; CCC between neighbour zero-crossing pair)
    i_enum += 1
    idx_cter_reserved = (
        i_enum
    )  # reserved spot for maximum frequency limit or error criterion. possibly originated from external program (e.g. CTF figure of merit of RELION)
    i_enum += 1
    idx_cter_const_ac = i_enum  # constant amplitude contrast [%]
    i_enum += 1
    idx_cter_phase_shift = i_enum  # phase shift [degrees]
    i_enum += 1
    idx_cter_mic_name = i_enum  # micrograph name (This must be always the last entry)
    i_enum += 1
    n_idx_cter = i_enum  # The number of CTER entires

    # For old SPHIRE CTF parameters file format
    n_idx_sphire_ctf = idx_cter_astig_ang + 1

    # ------------------------------------------------------------------------------------
    # STEP 1: Prepare input/output file paths
    # ------------------------------------------------------------------------------------
    # # Get the original current path
    # dir_origin = os.getcwd() # print dir_path_origin

    # Create work directories
    assert not os.path.exists(
        dir_path_work
    ), "# Logical Error: The output directory should not exists at this point of code."
    sp_global_def.sxprint("# Creating work dir...")
    os.makedirs(dir_path_work)
    sp_global_def.write_command(dir_path_work)

    if str_relion_start_section == 'data_particles':
        tmp_output = '{}_old.star'.format(os.path.join(dir_path_work, os.path.splitext(os.path.basename(file_path_relion_star))[0]))
        sp_global_def.sxprint('Try to create old-style star file')
        cmd = 'sp_convert_relionnew_to_relionold.py {} {}'.format(
                file_path_relion_star,
                tmp_output
                )
        sp_global_def.sxprint('Execute: {}'.format(cmd))
        return_code = subprocess.call(cmd.split())
        if return_code == 0:
            sp_global_def.sxprint('Succesfully converted to old-style star file')
            str_relion_start_section = 'data_'
            file_path_relion_star = tmp_output
        elif return_code == 1:
            sp_global_def.sxprint('Old style star file with particle data detected.')
            str_relion_start_section = 'data_particles'
        elif return_code == 2:
            sp_global_def.sxprint('Old style star file detected.')
            str_relion_start_section = 'data_'
        else:
            assert False, 'Please contact the SPHIRE developers'


    # ------------------------------------------------------------------------------------
    # STEP 2: Convert RELION parameters to SPHIRE format
    # ------------------------------------------------------------------------------------

    # Initialise loop variables
    is_found_section = False
    is_found_loop = False
    is_success = True
    i_relion_item_col = 0  # Counter for number of RELION items/columns
    i_relion_particle = (
        0
    )  # Counter for number of RELION particles/entries, starting from 0
    i_sphire_stack_ctf = (
        0
    )  # Counter for number of SPHIRE stack CTF entries, starting from 0
    i_sphire_stack_coordinates = (
        0
    )  # Counter for number of SPHIRE stack coordinates entries, starting from 0
    i_sphire_stack_proj3d = (
        0
    )  # Counter for number of SPHIRE stack 3D projection entries, starting from 0
    i_sphire_stack_particle_img = (
        0
    )  # Counter for number of particle image added to SPHIRE stack, starting from 0

    ### #
    ### # NOTE: Toshio Moriya 2017/11/20
    ### # In future, sphire_coordinates_dict and sphire_cter_dict should be put together under sphire_mic_dict
    ### # with following organization.
    ### # Level 0 key: micrograph_basename
    ### # Level 1 key: cter
    ### # Level 1 key: helical_tube_id (or particle group ID or coordinate group)?
    ### # Level 2 key: filament info = [relion_helical_tube_id, relion_ang_tilt_prior, relion_ang_pshi_prior, relion_helical_track_len, relion_ang_psi_flip_ratio].
    ### # Level 2 key: coordinates = [[relion_coordinate_x, relion_coordinate_y], ... ].  Under this, store the list of coordinates as the entries
    ### #
    ### # However, for now, organize sphire_coordinates_dict like below:
    ### # Standard SPA Coordinate File
    ### # Level 0 key: micrograph_basename
    ### # Level 1 key: coordinates = [[relion_coordinate_x, relion_coordinate_y], ... ].  Under this, store the list of coordinates as the entries
    ### #
    ### # Helical SPA Coordinate File
    ### # Level 0 key: micrograph_basename
    ### # Level 1 key: helical_tube_id (or particle group ID or coordinate group)?
    ### # Level 2 key: coordinates = [[relion_coordinate_x, relion_coordinate_y], ... ].  Under this, store the list of coordinates as the entries
    ### #
    sphire_micrographs_dict = (
        {}
    )  # For micrograph selecting list (one entry for each micrograph)
    sphire_cter_dict = (
        {}
    )  # For CTF parameters in CTER format (one list for each micrograph)
    sphire_coordinates_dict = (
        {}
    )  # For coordinate parameters (one list of entries for each micrograph)
    sphire_proj3d_dict = (
        {}
    )  # For projection parameters (one list of entries for each micrograph)
    sphire_chunk_dict = {}
    if is_enable_create_stack:
        sphire_header_dict = (
            {}
        )  # For headers of particle images (one list of entries for each micrograph)

    # Open input/output files
    assert os.path.exists(
        file_path_relion_star
    ), "# Logical Error: Input RELION STAR file must exits at this point of code."
    file_relion_star = open(file_path_relion_star, "r")

    # Loop through all lines in input RELION STAR file
    per_particle_ctf = []
    for i_line, str_line in enumerate(file_relion_star):

        # First, find data section in STAR file
        if is_found_section == False:
            if str_line.find(str_relion_start_section) != -1:
                sp_global_def.sxprint("# Title: %s" % (str_line.rstrip("\n")))
                is_found_section = True
        # Then, ignore loop_ in STAR file
        elif is_found_loop == False:
            assert (
                is_found_section == True
            ), "# Logical Error: The deta section must have been found at this point of code."
            if str_line.find("loop_") != -1:
                is_found_loop = True
                sp_global_def.sxprint("# Extracted Column IDs:")
        # Process item list and data entries
        else:
            assert (
                is_found_section and is_found_loop
            ), "# Logical Error: The deta and loop sections must have been found at this point of code."
            tokens_line = str_line.split()  # print tokens_line
            n_tokens_line = len(tokens_line)

            # First, check item list and find the column number of each item
            if str_line.find("_rln") != -1:
                i_relion_item_col += 1
                # print '# DEBUG: updated Column Counts := %d ' % (i_relion_item_col)

                relion_key = str_line.split(" ")[0]
                assert relion_key.find("_rln") != -1, (
                    "# Logical Error: The string %s must contain _rln at this point of code."
                    % (str_line)
                )

                if relion_key in list(relion_dict.keys()):
                    relion_dict[relion_key][idx_col] = int(i_relion_item_col)
                    sp_global_def.sxprint(
                        relion_dict[relion_key][idx_title]
                        % (relion_dict[relion_key][idx_col], relion_key)
                    )

            # Then, read the data entries
            elif n_tokens_line == i_relion_item_col:
                # Check if all entries of each category were found in RELION STAR file
                # Do this only once
                if i_relion_particle == 0:
                    sp_global_def.sxprint("# ")
                    sp_global_def.sxprint("# Checking RELION STAR file contents ...")
                    for category_key in list(relion_category_dict.keys()):
                        for key in relion_category_dict[category_key][
                            idx_required_key_list
                        ]:
                            if relion_dict[key][idx_col] < 0:
                                sp_global_def.sxprint(
                                    "#     %s entry for %s is not found"
                                    % (
                                        key,
                                        relion_category_dict[category_key][
                                            idx_relion_process
                                        ],
                                    )
                                )
                                relion_category_dict[category_key][
                                    idx_is_category_found
                                ] = False
                        if (
                            relion_category_dict[category_key][idx_is_category_found]
                            == True
                        ):
                            for key in relion_category_dict[category_key][
                                idx_denpended_key_list
                            ]:
                                if (
                                    relion_category_dict[key][idx_is_category_found]
                                    == False
                                ):
                                    sp_global_def.sxprint(
                                        "#     %s required for %s is not found"
                                        % (
                                            relion_category_dict[key][
                                                idx_relion_process
                                            ],
                                            relion_category_dict[category_key][
                                                idx_relion_process
                                            ],
                                        )
                                    )
                                    relion_category_dict[category_key][
                                        idx_is_category_found
                                    ] = False

                    if relion_category_dict["mic"][idx_is_category_found] == False:
                        sp_global_def.sxprint("# ")
                        sp_global_def.sxprint(
                            "# ERROR!!! Input STAR file must contain all entries for %s as the minimum requirement. Aborting execution ..."
                            % (relion_category_dict["mic"][idx_relion_process])
                        )
                        is_success = False
                        break

                    for category_key in list(relion_category_dict.keys()):
                        if (
                            relion_category_dict[category_key][idx_is_category_found]
                            == True
                        ):
                            sp_global_def.sxprint("# ")
                            sp_global_def.sxprint(
                                "# Parameters associated with %s will be extracted."
                                % (
                                    relion_category_dict[category_key][
                                        idx_relion_process
                                    ]
                                )
                            )
                            if category_key == "helical":
                                assert (
                                    relion_category_dict["window"][
                                        idx_is_category_found
                                    ]
                                    == True
                                ), "# Logical Error: This must be true at this point of code."
                                sp_global_def.sxprint(
                                    "#     NOTE: %s is under development!!!"
                                    % (
                                        relion_category_dict["helical"][
                                            idx_relion_process
                                        ]
                                    )
                                )
                                sp_global_def.sxprint(
                                    "#           Only the information necessary for SPHIRE helical reconstruction development will be stored in the image header."
                                )
                                assert (
                                    is_success == True
                                ), "# Logical Error: This must be true at this point of code."
                        else:
                            assert (
                                relion_category_dict[category_key][
                                    idx_is_category_found
                                ]
                                == False
                            ), "# Logical Error: This must be true at this point of code."
                            sp_global_def.sxprint("# ")
                            sp_global_def.sxprint(
                                "# WARNING!!! %s cannot be extracted!!! Some of required paramters are missing (see above)."
                                % (
                                    relion_category_dict[category_key][
                                        idx_relion_process
                                    ]
                                )
                            )
                    sp_global_def.sxprint("# ")

                    if (
                        is_enable_create_stack
                        and not relion_category_dict["window"][idx_is_category_found]
                    ):
                        sp_global_def.sxprint(
                            "# WARNING!!! Input STAR file must contain at least all entries for %s and %s to create a particle stack!!! No stack will be created."
                            % (
                                relion_category_dict["mic"][idx_relion_process],
                                relion_category_dict["window"][idx_relion_process],
                            )
                        )
                        sp_global_def.sxprint("# ")
                        is_enable_create_stack = False

                if i_relion_particle % 1000 == 0:
                    sp_global_def.sxprint(
                        "# Processing RELION entries from %7d to %7d ..."
                        % (i_relion_particle, i_relion_particle + 1000 - 1)
                    )

                ##### Store micrograph related parameters #####
                # Micrograph must be found always.
                assert relion_category_dict["mic"][
                    idx_is_category_found
                ], "# Logical Error: Micrograph information must be found any type of RELION STAR file at this point of code."
                relion_micrograph_name = tokens_line[
                    relion_dict["_rlnMicrographName"][idx_col] - 1
                ]
                micrograph_path = relion_micrograph_name
                micrograph_dirname, micrograph_basename = os.path.split(
                    relion_micrograph_name
                )
                adjusted_relion_micrograph_name = relion_micrograph_name
                if dir_path_relion_project is not None:
                    adjusted_relion_micrograph_name = os.path.join(
                        dir_path_relion_project, adjusted_relion_micrograph_name
                    )

                if micrograph_dirname not in sphire_micrographs_dict:
                    sphire_micrographs_dict[micrograph_dirname] = {}
                assert micrograph_dirname in sphire_micrographs_dict

                if (
                    micrograph_basename
                    not in sphire_micrographs_dict[micrograph_dirname]
                ):
                    sphire_micrographs_dict[micrograph_dirname][
                        micrograph_basename
                    ] = micrograph_basename
                else:
                    assert (
                        cmp(
                            sphire_micrographs_dict[micrograph_dirname][
                                micrograph_basename
                            ],
                            micrograph_basename,
                        )
                        == 0
                    ), (
                        "# Logical Error: key of sphire_micrographs_dict %s in %s and micrograph_basename %s must be identical."
                        % (
                            sphire_micrographs_dict[micrograph_dirname][
                                micrograph_basename
                            ],
                            micrograph_dirname,
                            micrograph_basename,
                        )
                    )

                if relion_category_dict["ctf"][idx_is_category_found] == True:
                    ##### Store CTF related parameters #####
                    # Parse this entry line and covert the parameters from RELION to SPHIRE formats
                    sphire_cter_entry = {}

                    relion_defocusU = float(
                        tokens_line[relion_dict["_rlnDefocusU"][idx_col] - 1]
                    )
                    relion_defocusV = float(
                        tokens_line[relion_dict["_rlnDefocusV"][idx_col] - 1]
                    )
                    relion_defocus_angle = float(
                        tokens_line[relion_dict["_rlnDefocusAngle"][idx_col] - 1]
                    )

                    sphire_cter_entry[idx_cter_def] = old_div(
                        (relion_defocusU + relion_defocusV), 20000
                    )  # convert format from RELION to SPHIRE
                    sphire_cter_entry[idx_cter_astig_amp] = old_div(
                        (-relion_defocusU + relion_defocusV), 10000
                    )  # convert format from RELION to SPHIRE
                    sphire_cter_entry[idx_cter_astig_ang] = (
                        45.0 - relion_defocus_angle
                    )  # convert format from RELION to SPHIRE
                    while sphire_cter_entry[idx_cter_astig_ang] >= 180:
                        sphire_cter_entry[idx_cter_astig_ang] -= 180
                    while sphire_cter_entry[idx_cter_astig_ang] < 0:
                        sphire_cter_entry[idx_cter_astig_ang] += 180

                    relion_const_ac = float(
                        tokens_line[relion_dict["_rlnAmplitudeContrast"][idx_col] - 1]
                    )
                    sphire_cter_entry[idx_cter_const_ac] = (
                        100 * relion_const_ac
                    )  # convert to %

                    if relion_dict["_rlnPhaseShift"][idx_col] >= 0:
                        relion_phase_shift = float(
                            tokens_line[relion_dict["_rlnPhaseShift"][idx_col] - 1]
                        )
                        sphire_cter_entry[
                            idx_cter_phase_shift
                        ] = relion_phase_shift  # in [degrees]
                    else:
                        sphire_cter_entry[idx_cter_phase_shift] = 0.0

                    sphire_const_ac_phase_shift = sp_morphology.ampcont2angle(
                        sphire_cter_entry[idx_cter_const_ac]
                    )  # must pass amplitude contrast in [%]
                    sphire_total_phase_shift = (
                        sphire_cter_entry[idx_cter_phase_shift]
                        + sphire_const_ac_phase_shift
                    )
                    sphire_cter_entry[idx_cter_total_ac] = sp_morphology.angle2ampcont(
                        sphire_total_phase_shift
                    )

                    sphire_cter_entry[idx_cter_vol] = float(
                        tokens_line[relion_dict["_rlnVoltage"][idx_col] - 1]
                    )
                    sphire_cter_entry[idx_cter_cs] = float(
                        tokens_line[relion_dict["_rlnSphericalAberration"][idx_col] - 1]
                    )

                    relion_det_pix_size = float(
                        tokens_line[relion_dict["_rlnDetectorPixelSize"][idx_col] - 1]
                    )
                    relion_mag = float(
                        tokens_line[relion_dict["_rlnMagnification"][idx_col] - 1]
                    )
                    sphire_cter_entry[idx_cter_apix] = old_div(
                        10000 * relion_det_pix_size, relion_mag
                    )  # convert um to A

                    ##### Store CTER specific parameters #####
                    sphire_cter_entry[
                        idx_cter_bfactor
                    ] = 0.0  # RELION does not output B-Factor, so set it zero always
                    sphire_cter_entry[idx_cter_sd_def] = 0.0
                    sphire_cter_entry[idx_cter_sd_total_ac] = 0.0
                    sphire_cter_entry[idx_cter_sd_astig_amp] = 0.0
                    sphire_cter_entry[idx_cter_sd_astig_ang] = 0.0
                    sphire_cter_entry[idx_cter_cv_def] = 0.0
                    sphire_cter_entry[idx_cter_cv_astig_amp] = 0.0
                    sphire_cter_entry[idx_cter_error_def] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_error_astig] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_error_ctf] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency

                    ##### Store max frequency limit related parameters #####
                    if relion_dict["_rlnCtfMaxResolution"][idx_col] >= 0:
                        sphire_cter_entry[idx_cter_max_freq] = float(
                            tokens_line[
                                relion_dict["_rlnCtfMaxResolution"][idx_col] - 1
                            ]
                        )
                    else:
                        sphire_cter_entry[idx_cter_max_freq] = old_div(
                            0.5, sphire_cter_entry[idx_cter_apix]
                        )  # Set to Nyquist frequency

                    if relion_dict["_rlnCtfFigureOfMerit"][idx_col] >= 0:
                        sphire_cter_entry[idx_cter_reserved] = float(
                            tokens_line[
                                relion_dict["_rlnCtfFigureOfMerit"][idx_col] - 1
                            ]
                        )
                    else:
                        sphire_cter_entry[idx_cter_reserved] = 0.0

                    sphire_cter_entry[
                        idx_cter_mic_name
                    ] = adjusted_relion_micrograph_name
                    assert len(sphire_cter_entry) == n_idx_cter, (
                        "# Logical Error: The length of sphiret CTER entry %d must be always %d at this point of code."
                        % (len(sphire_cter_entry), n_idx_cter)
                    )

                    if micrograph_dirname not in sphire_cter_dict:
                        sphire_cter_dict[micrograph_dirname] = {}
                    assert micrograph_dirname in sphire_cter_dict

                    if micrograph_basename not in sphire_cter_dict[micrograph_dirname]:
                        sphire_cter_dict[micrograph_dirname][micrograph_basename] = [
                            sphire_cter_entry
                        ]
                    else:
                        # # Store one CTER entry for each micrograph
                        # assert len(sphire_cter_dict[micrograph_dirname][micrograph_basename]) >= 1
                        # assert cmp(sphire_cter_dict[micrograph_dirname][micrograph_basename][0], sphire_cter_entry) == 0, '# Logical Error: All CTF paramters value belong to the same micrograph %s must be identical.' % (micrograph_basename)
                        #
                        # Store all CTER entries (one CTER entry for each particle) to support per-particle defocus estimation
                        sphire_cter_dict[micrograph_dirname][
                            micrograph_basename
                        ].append(sphire_cter_entry)
                    per_particle_ctf.append([
                        sphire_cter_entry[idx_cter_def],
                        sphire_cter_entry[idx_cter_cs],
                        sphire_cter_entry[idx_cter_vol],
                        sphire_cter_entry[idx_cter_apix],
                        sphire_cter_entry[idx_cter_bfactor],
                        sphire_cter_entry[idx_cter_total_ac],
                        sphire_cter_entry[idx_cter_astig_amp],
                        sphire_cter_entry[idx_cter_astig_ang],
                        ])

                    i_sphire_stack_ctf += 1
                elif options.negative_stain:
                    relion_det_pix_size = float(
                        tokens_line[relion_dict["_rlnDetectorPixelSize"][idx_col] - 1]
                    )
                    relion_mag = float(
                        tokens_line[relion_dict["_rlnMagnification"][idx_col] - 1]
                    )
                    sphire_cter_entry = [None] * n_idx_cter
                    sphire_cter_entry[idx_cter_def] = 0.0
                    sphire_cter_entry[idx_cter_cs] = 0.0
                    sphire_cter_entry[idx_cter_vol] = 300.0
                    sphire_cter_entry[idx_cter_apix] = old_div(
                        10000 * relion_det_pix_size, relion_mag
                    )  # convert um to A
                    sphire_cter_entry[idx_cter_bfactor] = 0.0
                    sphire_cter_entry[idx_cter_total_ac] = 100.0
                    sphire_cter_entry[idx_cter_astig_amp] = 0.0
                    sphire_cter_entry[idx_cter_astig_ang] = 0.0
                    sphire_cter_entry[idx_cter_sd_def] = 0.0
                    sphire_cter_entry[idx_cter_sd_total_ac] = 0.0
                    sphire_cter_entry[idx_cter_sd_astig_amp] = 0.0
                    sphire_cter_entry[idx_cter_sd_astig_ang] = 0.0
                    sphire_cter_entry[idx_cter_cv_def] = 0.0
                    sphire_cter_entry[idx_cter_cv_astig_amp] = 0.0
                    sphire_cter_entry[idx_cter_error_def] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_error_astig] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_error_ctf] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_max_freq] = old_div(
                        0.5, sphire_cter_entry[idx_cter_apix]
                    )  # Set to Nyquist frequency
                    sphire_cter_entry[idx_cter_reserved] = 0.0
                    sphire_cter_entry[idx_cter_const_ac] = 0.0
                    sphire_cter_entry[idx_cter_phase_shift] = 0.0
                    sphire_cter_entry[idx_cter_mic_name] = ""

                if relion_category_dict["window"][idx_is_category_found]:
                    relion_particle_source = tokens_line[
                        relion_dict["_rlnImageName"][idx_col] - 1
                    ]
                    tokens_particle_source = relion_particle_source.split("@")
                    assert len(tokens_particle_source) == 2, (
                        "# Logical Error: The format of this string item %s is not as assumed."
                        % relion_particle_source
                    )

                    relion_local_particle_id = int(tokens_particle_source[0])
                    sphire_local_particle_id = (
                        relion_local_particle_id - 1
                    )  # Local Particle ID of RELION from 1 but SPHIRE from 0 (In SPHIRE, all ID should start from 0)
                    relion_local_stack_path = tokens_particle_source[1]
                    if dir_path_relion_project is not None:
                        relion_local_stack_path = os.path.join(
                            dir_path_relion_project, relion_local_stack_path
                        )  # Adjust the path with RELION project directory path relative to current directory

                    ##### Store box coordinate related parameters #####
                    relion_coordinate_x = int(
                        float(tokens_line[relion_dict["_rlnCoordinateX"][idx_col] - 1])
                    )
                    relion_coordinate_y = int(
                        float(tokens_line[relion_dict["_rlnCoordinateY"][idx_col] - 1])
                    )

                    # Standard SPA Coordinate File
                    if relion_category_dict["helical"][idx_is_category_found] == False:
                        sphire_coordinates = [0] * n_idx_ptcl_source
                        sphire_coordinates[
                            idx_ptcl_source_coord_id
                        ] = sphire_local_particle_id
                        sphire_coordinates[
                            idx_ptcl_source_coord_x
                        ] = relion_coordinate_x
                        sphire_coordinates[
                            idx_ptcl_source_coord_y
                        ] = relion_coordinate_y
                        sphire_coordinates[idx_ptcl_source_resample_ratio] = 1.0
                        sphire_coordinates[idx_ptcl_source_filament_id] = 0

                        if micrograph_dirname not in sphire_coordinates_dict:
                            sphire_coordinates_dict[micrograph_dirname] = {}
                        assert micrograph_dirname in sphire_coordinates_dict

                        # No conversion is necessary from RELION to SPHIRE formats
                        if (
                            micrograph_basename
                            in sphire_coordinates_dict[micrograph_dirname]
                        ):
                            sphire_coordinates_dict[micrograph_dirname][
                                micrograph_basename
                            ].append(sphire_coordinates)
                        else:
                            sphire_coordinates_dict[micrograph_dirname][
                                micrograph_basename
                            ] = [sphire_coordinates]
                    # Helical SPA Coordinate File
                    else:
                        assert (
                            relion_category_dict["helical"][idx_is_category_found]
                            == True
                        ), "# Logical Error: This statment must be true at this point of code."
                        ##### Store helical tube extraction related parameters #####
                        relion_helical_tube_id = int(
                            tokens_line[relion_dict["_rlnHelicalTubeID"][idx_col] - 1]
                        )
                        sphire_filament_id = (
                            relion_helical_tube_id - 1
                        )  # In SPHIRE, all ID should start from 0
                        ### #
                        ### # NOTE: Toshio Moriya 2017/11/20
                        ### # The followings are for future and unused now.
                        ### # Also see note above the declaration of sphire_coordinates_dict
                        ### #
                        ### relion_ang_tilt_prior = float(tokens_line[relion_dict['_rlnAngleTiltPrior'][idx_col] - 1])
                        ### relion_ang_pshi_prior = float(tokens_line[relion_dict['_rlnAnglePsiPrior'][idx_col] - 1])
                        ### relion_helical_track_len = float(tokens_line[relion_dict['_rlnHelicalTrackLength'][idx_col] - 1])
                        ### relion_ang_psi_flip_ratio = float(tokens_line[relion_dict['_rlnAnglePsiFlipRatio'][idx_col] - 1])

                        sphire_coordinates = [0] * n_idx_ptcl_source
                        sphire_coordinates[
                            idx_ptcl_source_coord_id
                        ] = sphire_local_particle_id
                        sphire_coordinates[
                            idx_ptcl_source_coord_x
                        ] = relion_coordinate_x
                        sphire_coordinates[
                            idx_ptcl_source_coord_y
                        ] = relion_coordinate_y
                        sphire_coordinates[idx_ptcl_source_resample_ratio] = 1.0
                        sphire_coordinates[
                            idx_ptcl_source_filament_id
                        ] = sphire_filament_id

                        if micrograph_dirname not in sphire_coordinates_dict:
                            sphire_coordinates_dict[micrograph_dirname] = {}
                        assert micrograph_dirname in sphire_coordinates_dict

                        if (
                            micrograph_basename
                            in sphire_coordinates_dict[micrograph_dirname]
                        ):
                            if (
                                sphire_filament_id
                                in sphire_coordinates_dict[micrograph_dirname][
                                    micrograph_basename
                                ]
                            ):
                                sphire_coordinates_dict[micrograph_dirname][
                                    micrograph_basename
                                ][sphire_filament_id].append(sphire_coordinates)
                            else:
                                sphire_coordinates_dict[micrograph_dirname][
                                    micrograph_basename
                                ][sphire_filament_id] = [sphire_coordinates]
                        else:
                            sphire_filament_dict = {}
                            sphire_filament_dict[sphire_filament_id] = [
                                sphire_coordinates
                            ]
                            sphire_coordinates_dict[micrograph_dirname][
                                micrograph_basename
                            ] = sphire_filament_dict

                    i_sphire_stack_coordinates += 1

                if relion_category_dict["proj3d"][idx_is_category_found]:
                    ##### Store Projection related parameters #####
                    relion_tx = float(
                        tokens_line[relion_dict["_rlnOriginX"][idx_col] - 1]
                    )
                    relion_ty = float(
                        tokens_line[relion_dict["_rlnOriginY"][idx_col] - 1]
                    )
                    relion_rot = float(
                        tokens_line[relion_dict["_rlnAngleRot"][idx_col] - 1]
                    )
                    relion_tilt = float(
                        tokens_line[relion_dict["_rlnAngleTilt"][idx_col] - 1]
                    )
                    relion_psi = float(
                        tokens_line[relion_dict["_rlnAnglePsi"][idx_col] - 1]
                    )

                    relion_max_prob_dist = float(
                        tokens_line[
                            relion_dict["_rlnMaxValueProbDistribution"][idx_col] - 1
                        ]
                    )
                    relion_norm_correct = float(
                        tokens_line[relion_dict["_rlnNormCorrection"][idx_col] - 1]
                    )

                    relion_trans3d = EMAN2_cppwrap.Transform(
                        {
                            "phi": relion_rot,
                            "theta": relion_tilt,
                            "omega": relion_psi,
                            "tx": relion_tx,
                            "ty": relion_ty,
                            "type": "mrc",
                            "tz": 0,
                        }
                    )
                    sphire_proj3d = relion_trans3d.get_params("spider")
                    # file_sphire_stack_proj3d.write('%12.6f %12.6f %12.6f %12.6f %12.6f %12.6f %12.6f\n' % (sphire_proj3d['phi'], sphire_proj3d['theta'], sphire_proj3d['psi'], sphire_proj3d['tx'], sphire_proj3d['ty'], relion_max_prob_dist, relion_norm_correct))

                    if micrograph_dirname not in sphire_proj3d_dict:
                        sphire_proj3d_dict[micrograph_dirname] = {}
                    assert micrograph_dirname in sphire_proj3d_dict

                    # No conversion is necessary from RELION to SPHIRE formats
                    if micrograph_basename in sphire_proj3d_dict[micrograph_dirname]:
                        sphire_proj3d_dict[micrograph_dirname][
                            micrograph_basename
                        ].append(sphire_proj3d)
                    else:
                        sphire_proj3d_dict[micrograph_dirname][micrograph_basename] = [
                            sphire_proj3d
                        ]

                    i_sphire_stack_proj3d += 1

                if relion_category_dict["chunk"][idx_is_category_found]:
                    ##### Store the entry id (particle id) in the corresponding halfset #####
                    # relion_random_subset starts from 1 in RELION
                    relion_random_subset = int(
                        tokens_line[relion_dict["_rlnRandomSubset"][idx_col] - 1]
                    )
                    sphire_chunk_id = (
                        relion_random_subset - 1
                    )  # Chunk ID starts from 0 in SPHIRE

                    if micrograph_dirname not in sphire_chunk_dict:
                        sphire_chunk_dict[micrograph_dirname] = {}
                    assert micrograph_dirname in sphire_chunk_dict

                    if micrograph_basename in sphire_chunk_dict[micrograph_dirname]:
                        sphire_chunk_dict[micrograph_dirname][
                            micrograph_basename
                        ].append(sphire_chunk_id)
                    else:
                        sphire_chunk_dict[micrograph_dirname][micrograph_basename] = [
                            sphire_chunk_id
                        ]

                    # sphire_chunk_key = '%1d' % sphire_chunk_id
                    # if (sphire_chunk_key in sphire_chunk_dict) == False:
                    # 	sphire_chunk_dict[micrograph_dirname][sphire_chunk_key] = []
                    # sphire_chunk_dict[micrograph_dirname][sphire_chunk_key].append(i_relion_particle)

                ##### Set the header information #####
                if is_enable_create_stack:
                    assert relion_category_dict["window"][
                        idx_is_category_found
                    ], "MRK_DEBUG"

                    # Now read image
                    if not os.path.exists(relion_local_stack_path):
                        sp_global_def.sxprint(
                            "# WARNING!!! Image name %s specified in STAR file is not found from the current directory. Skipping STAR file entry %d..."
                            % (relion_local_stack_path, i_relion_particle)
                        )
                    else:
                        sphire_header = {}
                        sphire_header[
                            "relion_local_stack_path"
                        ] = relion_local_stack_path
                        sphire_header[
                            "sphire_local_particle_id"
                        ] = sphire_local_particle_id

                        # NOTE: 2015/10/19 Toshio Moriya
                        # Now storing the extracted information in the sphire header dictionary
                        sphire_header["ptcl_source_relion"] = relion_particle_source
                        sphire_header[
                            "ptcl_source_image"
                        ] = adjusted_relion_micrograph_name
                        sphire_header["ptcl_source_coord"] = [
                            relion_coordinate_x,
                            relion_coordinate_y,
                        ]  # No conversion is necessary from RELION to SPHIRE foramts
                        sphire_header["ptcl_source_coord_id"] = sphire_local_particle_id
                        sphire_header[
                            "data_n"
                        ] = (
                            sphire_local_particle_id
                        )  # NOTE: Toshio Moriya 2017/11/20: same as ptcl_source_coord_id but the other program uses this header entry key...
                        sphire_header["resample_ratio"] = 1.0
                        sphire_header["apix_x"] = 1.0
                        sphire_header["apix_y"] = 1.0
                        sphire_header["apix_z"] = 1.0

                        if relion_category_dict["helical"][idx_is_category_found]:
                            sphire_header["filament_id"] = "{0}{1:05d}".format(
                                adjusted_relion_micrograph_name, sphire_filament_id
                            )
                            sphire_header["segment_id"] = sphire_local_particle_id
                            sphire_header["filament_track_length"] = float(
                                tokens_line[
                                    relion_dict["_rlnHelicalTrackLength"][idx_col] - 1
                                ]
                            )
                            if relion_dict["_rlnAnglePsiPrior"][idx_col] == -1:
                                sphire_header["segment_angle"] = None
                            else:
                                sphire_header["segment_angle"] = float(
                                    tokens_line[
                                        relion_dict["_rlnAnglePsiPrior"][idx_col] - 1
                                    ]
                                )
                        if (
                            relion_category_dict["ctf"][idx_is_category_found]
                            or options.negative_stain
                        ):
                            sphire_cter_entry_list = []
                            for idx_sphire_ctf in range(n_idx_sphire_ctf):
                                sphire_cter_entry_list.append(
                                    sphire_cter_entry[idx_sphire_ctf]
                                )
                            sphire_header["ctf"] = sp_utilities.generate_ctf(
                                sphire_cter_entry_list
                            )
                            sphire_header["ctf_applied"] = 0
                            sphire_header["ptcl_source_apix"] = sphire_cter_entry[
                                idx_cter_apix
                            ]  # Store the original pixel size
                        if relion_category_dict["proj3d"][idx_is_category_found]:
                            sphire_header["xform.projection"] = [
                                sphire_proj3d["phi"],
                                sphire_proj3d["theta"],
                                sphire_proj3d["psi"],
                                sphire_proj3d["tx"],
                                sphire_proj3d["ty"],
                            ]
                            # Add relion specific header entries
                            sphire_header["relion_max_prob_dist"] = relion_max_prob_dist
                            sphire_header["relion_norm_correct"] = relion_norm_correct
                        if relion_category_dict["chunk"][idx_is_category_found]:
                            sphire_header["chunk_id"] = sphire_chunk_id

                        sphire_header[
                            "i_sphire_stack_particle_img"
                        ] = i_sphire_stack_particle_img

                        if micrograph_dirname not in sphire_header_dict:
                            sphire_header_dict[micrograph_dirname] = {}
                        assert micrograph_dirname in sphire_header_dict

                        if (
                            micrograph_basename
                            in sphire_header_dict[micrograph_dirname]
                        ):
                            sphire_header_dict[micrograph_dirname][
                                micrograph_basename
                            ].append(sphire_header)
                        else:
                            sphire_header_dict[micrograph_dirname][
                                micrograph_basename
                            ] = [sphire_header]

                        i_sphire_stack_particle_img += 1

                i_relion_particle += 1

            else:
                sp_global_def.sxprint(
                    "# An empty line is detected after data entries. Breaking the loop..."
                )
                break

    if is_found_section == False:
        sp_global_def.sxprint(
            "# ERROR!!! Specified --star_section (%s) is not found!!!"
            % (str_relion_start_section)
        )
        sp_global_def.sxprint("#          Please check section name in STAR file.")
        is_success = False
    elif is_found_loop == False:
        sp_global_def.sxprint(
            "# ERROR!!! loop_ line after specified --star_section (%s) is not found!!!"
            % (str_relion_start_section)
        )
        sp_global_def.sxprint("#          Please check if STAR file is not corrupted.")
        is_success = False

    if is_success:
        # Store the results of counters
        sphire_micrographs_dict_dirname_counts = len(sphire_micrographs_dict)
        sphire_mircrograph_entry_total_counts = 0
        for sphire_micrograph_dirname in sphire_micrographs_dict:
            sphire_mircrograph_entry_total_counts += len(
                sphire_micrographs_dict[sphire_micrograph_dirname]
            )

        sphire_cter_dict_dirname_counts = len(sphire_cter_dict)
        sphire_cter_entry_total_counts = 0
        for sphire_micrograph_dirname in sphire_cter_dict:
            sphire_cter_entry_total_counts += len(
                sphire_cter_dict[sphire_micrograph_dirname]
            )

        sphire_coordinates_dict_dirname_counts = len(sphire_coordinates_dict)
        sphire_coordinates_entry_total_counts = 0
        for sphire_micrograph_dirname in sphire_coordinates_dict:
            sphire_coordinates_entry_total_counts += len(
                sphire_coordinates_dict[sphire_micrograph_dirname]
            )

        sphire_proj3d_dict_dirname_counts = len(sphire_proj3d_dict)
        sphire_proj3d_entry_total_counts = 0
        for sphire_micrograph_dirname in sphire_proj3d_dict:
            sphire_proj3d_entry_total_counts += len(
                sphire_proj3d_dict[sphire_micrograph_dirname]
            )

        sphire_chunk_dict_dirname_counts = len(sphire_chunk_dict)
        sphrie_chunk_id_total_counts = 0
        for sphire_micrograph_dirname in sphire_chunk_dict:
            sphrie_chunk_id_total_counts += len(
                sphire_chunk_dict[sphire_micrograph_dirname]
            )

        if is_enable_create_stack:
            sphire_header_dict_dirname_counts = len(sphire_header_dict)
            sphire_header_total_counts = 0
            for sphire_micrograph_dirname in sphire_header_dict:
                sphire_header_total_counts += len(
                    sphire_header_dict[sphire_micrograph_dirname]
                )

        sp_global_def.sxprint("# ")
        sp_global_def.sxprint(
            "# Detected RELION column counts                     := {} ".format(
                i_relion_item_col
            )
        )
        sp_global_def.sxprint(
            "# Detected RELION entry counts                      := {} ".format(
                i_relion_particle
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE mircrograph directory counts     := {} ".format(
                sphire_micrographs_dict_dirname_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE mircrograph entry total counts   := {} ".format(
                sphire_mircrograph_entry_total_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE CTER directory counts            := {} ".format(
                sphire_cter_dict_dirname_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE CTER entry total counts          := {} ".format(
                sphire_cter_entry_total_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE coorinates directory counts      := {} ".format(
                sphire_coordinates_dict_dirname_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE coorinates entry total counts    := {} ".format(
                sphire_coordinates_entry_total_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE 3D projection directory counts   := {} ".format(
                sphire_proj3d_dict_dirname_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE 3D projection entry total counts := {} ".format(
                sphire_proj3d_entry_total_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE chunk directory counts           := {} ".format(
                sphire_chunk_dict_dirname_counts
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE chunk ID total counts            := {} ".format(
                sphrie_chunk_id_total_counts
            )
        )

        if is_enable_create_stack:
            sp_global_def.sxprint(
                "# Processed SPHIRE header directory counts          := {} ".format(
                    sphire_header_dict_dirname_counts
                )
            )
            sp_global_def.sxprint(
                "# Processed SPHIRE header total counts              := {} ".format(
                    sphire_header_total_counts
                )
            )

        sp_global_def.sxprint(
            "# Processed SPHIRE stack CTF entry counts           := {} ".format(
                i_sphire_stack_ctf
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE stack coorinates entry counts    := {} ".format(
                i_sphire_stack_coordinates
            )
        )
        sp_global_def.sxprint(
            "# Processed SPHIRE stack 3D Proj. entry counts      := {} ".format(
                i_sphire_stack_proj3d
            )
        )
        sp_global_def.sxprint(
            "# Image counts added to SPHIRE stack                := {} ".format(
                i_sphire_stack_particle_img
            )
        )

        # Warn user if number of particles in SPHIRE stack is different from RELION STAR file entries
        if is_enable_create_stack:
            if i_sphire_stack_particle_img < i_relion_particle:
                sp_global_def.sxprint(
                    "# WARNING!!! The number of particles in generated stack (%d) is different from the number of entries in input RELION STAR file (%d)!!!"
                    % (i_relion_particle, i_sphire_stack_particle_img)
                )
                sp_global_def.sxprint(
                    "#            Please check if there are all images specified by _rlnImageName in STAR file"
                )
            else:
                assert (
                    i_sphire_stack_particle_img == i_relion_particle
                ), "# The number of particles must always match at this point of code."

        sp_global_def.sxprint("# ")
        sp_global_def.sxprint("# Saving SPHIRE parameters files ...")

        with open(os.path.join(dir_path_work, file_name_sphire_cter_per_particle), 'w') as write:
            write.write(
                '\n'.join(
                    ' '.join(map(str, ctf_entry))
                    for ctf_entry
                    in per_particle_ctf
                    )
                )


        # Write micrograph name to files (micrograph selection list file)
        for micrograph_dirname in sorted(sphire_micrographs_dict):
            dir_path_sphire_micrographs = os.path.join(
                dir_path_work,
                os.path.join(
                    *[entry for entry in micrograph_dirname.split("/") if entry != ".."]
                ),
            )
            if not os.path.exists(dir_path_sphire_micrographs):
                # Markus 05.06.18 -- os.mkdir(dir_path_sphire_micrographs)
                os.makedirs(dir_path_sphire_micrographs)

            file_path_sphire_micrographs = os.path.join(
                dir_path_sphire_micrographs, file_name_sphire_micrographs
            )
            file_sphire_micrographs = open(file_path_sphire_micrographs, "w+")
            for micrograph_basename in sorted(
                sphire_micrographs_dict[micrograph_dirname]
            ):
                file_sphire_micrographs.write("%s\n" % (micrograph_basename))
            file_sphire_micrographs.close()

        # Write CTER entry to files (doing here to avoid repeating open/close files in loop)
        for micrograph_dirname in sorted(sphire_cter_dict):
            dir_path_sphire_cter_partres = os.path.join(
                dir_path_work,
                os.path.join(
                    *[entry for entry in micrograph_dirname.split("/") if entry != ".."]
                ),
            )
            if not os.path.exists(dir_path_sphire_cter_partres):
                # Markus 05.06.18 -- os.mkdir(dir_path_sphire_micrographs)
                os.makedirs(dir_path_sphire_cter_partres)

            micrograph_extension = os.path.splitext(micrograph_basename)[1]
            file_path_sphire_cter_partres = os.path.join(
                dir_path_sphire_cter_partres, file_name_sphire_cter_partres
            )
            file_sphire_cter_partres = open(file_path_sphire_cter_partres, "w+")
            for micrograph_basename in sorted(sphire_cter_dict[micrograph_dirname]):
                assert (
                    len(sphire_cter_dict[micrograph_dirname][micrograph_basename]) >= 1
                )  # Should be one CTER entry for each micrograph

                # Compute statistics of CTF parameters for each micrograph
                sphire_cter_table = [[] for idx_cter in range(n_idx_cter)]
                assert len(sphire_cter_table) == n_idx_cter

                for sphire_cter_entry in sphire_cter_dict[micrograph_dirname][
                    micrograph_basename
                ]:
                    for idx_cter in range(n_idx_cter):
                        sphire_cter_table[idx_cter].append(sphire_cter_entry[idx_cter])

                sphire_cter_stats = sphire_cter_dict[micrograph_dirname][
                    micrograph_basename
                ][0]

                sphire_cter_stats[idx_cter_def], sd, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_def]
                )
                sphire_cter_stats[idx_cter_sd_def] = numpy.sqrt(max(0.0, sd))
                if sphire_cter_stats[idx_cter_def] != 0.0:
                    sphire_cter_stats[idx_cter_cv_def] = (
                        old_div(sd, sphire_cter_stats[idx_cter_def]) * 100
                    )  # use percentage
                # I removed a very awkward code which as far as I can tell was meant to assure that
                #   all values on this list are identical.  I replaced it by proper python
                #assert len(set(sphire_cter_table[idx_cter_cs])) == 1
                #assert len(set(sphire_cter_table[idx_cter_vol])) == 1
                #assert len(set(sphire_cter_table[idx_cter_apix])) == 1
                #assert len(set(sphire_cter_table[idx_cter_bfactor])) == 1

                sphire_cter_stats[
                    idx_cter_total_ac
                ], sd, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_total_ac]
                )
                sphire_cter_stats[idx_cter_sd_total_ac] = numpy.sqrt(max(0.0, sd))

                sphire_cter_stats[
                    idx_cter_astig_amp
                ], sd, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_astig_amp]
                )
                sphire_cter_stats[idx_cter_sd_astig_amp] = numpy.sqrt(max(0.0, sd))
                if sphire_cter_stats[idx_cter_astig_amp] != 0.0:
                    sphire_cter_stats[idx_cter_cv_astig_amp] = (
                        old_div(sd, sphire_cter_stats[idx_cter_astig_amp]) * 100
                    )  # use percentage

                # What followed was wrong, one cannot compute average angles this way PAP   01/28/2019
                sphire_cter_stats[idx_cter_astig_ang], sphire_cter_stats[
                    idx_cter_sd_astig_ang
                ] = sp_pixel_error.angle_ave(sphire_cter_table[idx_cter_astig_ang])

                sphire_cter_stats[
                    idx_cter_max_freq
                ], _, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_max_freq]
                )

                sphire_cter_stats[
                    idx_cter_reserved
                ], _, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_reserved]
                )

                sphire_cter_stats[
                    idx_cter_const_ac
                ], _, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_const_ac]
                )

                sphire_cter_stats[
                    idx_cter_phase_shift
                ], _, _, _ = sp_statistics.table_stat(
                    sphire_cter_table[idx_cter_phase_shift]
                )

                # Save statistics of CTF parameters for each micrograph
                for idx_cter in range(n_idx_cter - 1):
                    file_sphire_cter_partres.write(
                        "  %13.6f" % sphire_cter_entry[idx_cter]
                    )
                file_sphire_cter_partres.write(
                    "  %s\n" % sphire_cter_entry[idx_cter_mic_name]
                )  # At the end of line, write micrograph name which is string type!

            file_sphire_cter_partres.close()

        # Write box coordinate to files (doing here to avoid repeating open/close files in loop)
        if box_size > 0:
            coordinates_extension = ".box"
        else:
            coordinates_extension = ".txt"
            assert (
                box_size <= 0
            ), "# Logical Error: Box size should be always zero or negative at this point of code."

        for micrograph_dirname in sorted(sphire_coordinates_dict):
            dir_path_coordinates = os.path.join(
                dir_path_work,
                os.path.join(
                    *[entry for entry in micrograph_dirname.split("/") if entry != ".."]
                ),
                dir_name_coordinates,
            )
            if not os.path.exists(dir_path_coordinates):
                os.makedirs(dir_path_coordinates)

            for micrograph_basename in sorted(
                sphire_coordinates_dict[micrograph_dirname]
            ):
                micrograph_extension = os.path.splitext(micrograph_basename)[1]
                file_path_coordinates = os.path.join(
                    dir_path_coordinates,
                    micrograph_basename.replace(
                        micrograph_extension, coordinates_extension
                    ),
                )
                file_coordinates = open(file_path_coordinates, "w+")

                # Standard SPA Coordinate File
                if relion_category_dict["helical"][idx_is_category_found] == False:
                    for sphire_coordinates in sphire_coordinates_dict[
                        micrograph_dirname
                    ][micrograph_basename]:
                        if box_size > 0:
                            # Convert coordinate from SPHIRE to eman1 foramts
                            eman1_coordinate_x = sphire_coordinates[
                                idx_ptcl_source_coord_x
                            ] - old_div(box_size, 2)
                            eman1_coordinate_y = sphire_coordinates[
                                idx_ptcl_source_coord_y
                            ] - old_div(box_size, 2)
                            eman1_dummy = -1  # For 5th column of EMAN1 boxer format
                            # in star file they are floats, so they have to be properly rounded,  PAP
                            file_coordinates.write(
                                "%6d %6d %6d %6d %6d\n"
                                % (
                                    int(round(eman1_coordinate_x)),
                                    int(round(eman1_coordinate_y)),
                                    box_size,
                                    box_size,
                                    eman1_dummy,
                                )
                            )
                        else:
                            # in star file they are floats, so they have to be properly rounded,  PAP
                            file_coordinates.write(
                                "%6d %6d\n"
                                % (
                                    int(
                                        round(
                                            sphire_coordinates[idx_ptcl_source_coord_x]
                                        )
                                    ),
                                    int(
                                        round(
                                            sphire_coordinates[idx_ptcl_source_coord_y]
                                        )
                                    ),
                                )
                            )
                else:
                    assert (
                        relion_category_dict["helical"][idx_is_category_found] == True
                    ), "# Logical Error: helical category must be found always at this point of code."
                    file_coordinates.write("#micrograph: %s\n" % (micrograph_basename))
                    file_coordinates.write("#segment length: %.1f\n" % (box_size))
                    file_coordinates.write("#segment width: %.1f\n" % (box_size))
                    for sphire_filament_id in sorted(
                        sphire_coordinates_dict[micrograph_dirname][micrograph_basename]
                    ):
                        #
                        # NOTE: Toshio Moriya 2017/11/21
                        # The order of coordinates must be sorted with x-coordinates, then y-coordinates  in SPHIRE helical SPA box file
                        #
                        sphire_coordinates_dict[micrograph_dirname][
                            micrograph_basename
                        ][sphire_filament_id].sort(
                            key=operator.itemgetter(1), reverse=False
                        )
                        sphire_coordinates_dict[micrograph_dirname][
                            micrograph_basename
                        ][sphire_filament_id].sort(
                            key=operator.itemgetter(0), reverse=False
                        )
                        head_sphire_coordinates = sphire_coordinates_dict[
                            micrograph_dirname
                        ][micrograph_basename][sphire_filament_id][0]
                        tail_sphire_coordinates = sphire_coordinates_dict[
                            micrograph_dirname
                        ][micrograph_basename][sphire_filament_id][-1]
                        # MRK_DEBUG: file_coordinates.write('#helix: (%.1f, %.1f),(%.1f, %.1f),%.1f %d\n' % (head_sphire_coordinates[idx_ptcl_source_coord_x], head_sphire_coordinates[idx_ptcl_source_coord_y], tail_sphire_coordinates[idx_ptcl_source_coord_x], tail_sphire_coordinates[idx_ptcl_source_coord_y], box_size, sphire_filament_id))
                        file_coordinates.write(
                            "#helix: (%.1f, %.1f),(%.1f, %.1f),%.1f\n"
                            % (
                                head_sphire_coordinates[idx_ptcl_source_coord_x],
                                head_sphire_coordinates[idx_ptcl_source_coord_y],
                                tail_sphire_coordinates[idx_ptcl_source_coord_x],
                                tail_sphire_coordinates[idx_ptcl_source_coord_y],
                                box_size,
                            )
                        )
                        for sphire_coordinates in sphire_coordinates_dict[
                            micrograph_dirname
                        ][micrograph_basename][sphire_filament_id]:
                            assert (
                                sphire_coordinates[idx_ptcl_source_filament_id]
                                == sphire_filament_id
                            )
                            file_coordinates.write(
                                "%.1f\t%.1f\n"
                                % (
                                    sphire_coordinates[idx_ptcl_source_coord_x],
                                    sphire_coordinates[idx_ptcl_source_coord_y],
                                )
                            )

                file_coordinates.close()

        if not relion_category_dict["helical"][idx_is_category_found]:

            if relion_category_dict["window"][idx_is_category_found]:
                # Write rebox parameters to files (doing here to avoid repeating open/close files in loop)
                sp_global_def.sxprint("# ")
                sp_global_def.sxprint("# Saving SPHIRE rebox files ...")

                rebox_extension = ".rbx"
                assert relion_category_dict["mic"][idx_is_category_found]

                # Prepare the dummy entries in case they are not listed in relion start file
                if not relion_category_dict["ctf"][idx_is_category_found]:
                    dummy_sphire_ctf_entry = [0.0] * n_idx_sphire_ctf
                    dummy_sphire_ctf_entry[idx_cter_def] = 0.0
                    dummy_sphire_ctf_entry[idx_cter_cs] = 0.0
                    dummy_sphire_ctf_entry[idx_cter_vol] = 300.0
                    dummy_sphire_ctf_entry[idx_cter_apix] = 1.0
                    dummy_sphire_ctf_entry[idx_cter_bfactor] = 0.0
                    dummy_sphire_ctf_entry[idx_cter_total_ac] = 100.0
                    dummy_sphire_ctf_entry[idx_cter_astig_amp] = 0.0
                    dummy_sphire_ctf_entry[idx_cter_astig_ang] = 0.0
                if not relion_category_dict["proj3d"][idx_is_category_found]:
                    dummy_sphire_proj3d = {}
                    dummy_sphire_proj3d["phi"] = 0.0
                    dummy_sphire_proj3d["theta"] = 0.0
                    dummy_sphire_proj3d["psi"] = 0.0
                    dummy_sphire_proj3d["tx"] = 0.0
                    dummy_sphire_proj3d["ty"] = 0.0
                if not relion_category_dict["chunk"][idx_is_category_found]:
                    dummy_sphire_chunk_id = 0

                dummy_particle_defocus_error = 0.0
                dummy_particle_resample_ratio = 1.0

                for micrograph_dirname in sorted(sphire_micrographs_dict):
                    dir_path_rebox = os.path.join(
                        dir_path_work,
                        os.path.join(
                            *[
                                entry
                                for entry in micrograph_dirname.split("/")
                                if entry != ".."
                            ]
                        ),
                        dir_name_rebox,
                    )
                    if not os.path.exists(dir_path_rebox):
                        os.makedirs(dir_path_rebox)

                    for micrograph_basename in sorted(
                        sphire_micrographs_dict[micrograph_dirname]
                    ):
                        micrograph_extension = os.path.splitext(micrograph_basename)[1]
                        file_path_rebox = os.path.join(
                            dir_path_rebox,
                            micrograph_basename.replace(
                                micrograph_extension, rebox_extension
                            ),
                        )
                        file_rebox = open(file_path_rebox, "w+")

                        assert micrograph_dirname in sphire_coordinates_dict
                        assert (
                            micrograph_basename
                            in sphire_coordinates_dict[micrograph_dirname]
                        )
                        sphire_coordinates_list = sphire_coordinates_dict[
                            micrograph_dirname
                        ][micrograph_basename]
                        n_sphire_rebox_entry = len(sphire_coordinates_list)

                        sphire_ctf_list = []
                        if relion_category_dict["ctf"][idx_is_category_found]:
                            assert micrograph_dirname in sphire_cter_dict
                            assert (
                                micrograph_basename
                                in sphire_cter_dict[micrograph_dirname]
                            )
                            sphire_ctf_list = sphire_cter_dict[micrograph_dirname][
                                micrograph_basename
                            ]
                        else:
                            # assert not relion_category_dict['ctf'][idx_is_category_found]
                            for i_sphire_rebox_entry in range(n_sphire_rebox_entry):
                                sphire_ctf_list.append(dummy_sphire_ctf_entry)
                        assert n_sphire_rebox_entry == len(sphire_ctf_list)

                        sphire_proj3d_list = []
                        if relion_category_dict["proj3d"][idx_is_category_found]:
                            assert micrograph_dirname in sphire_proj3d_dict
                            assert (
                                micrograph_basename
                                in sphire_proj3d_dict[micrograph_dirname]
                            )
                            sphire_proj3d_list = sphire_proj3d_dict[micrograph_dirname][
                                micrograph_basename
                            ]
                        else:
                            # assert not relion_category_dict['proj3d'][idx_is_category_found]
                            for i_sphire_rebox_entry in range(n_sphire_rebox_entry):
                                sphire_proj3d_list.append(dummy_sphire_proj3d)
                        assert n_sphire_rebox_entry == len(sphire_proj3d_list)

                        sphire_chunk_id_list = []
                        if relion_category_dict["chunk"][idx_is_category_found]:
                            assert micrograph_dirname in sphire_chunk_dict
                            assert (
                                micrograph_basename
                                in sphire_chunk_dict[micrograph_dirname]
                            )
                            sphire_chunk_id_list = sphire_chunk_dict[
                                micrograph_dirname
                            ][micrograph_basename]
                        else:
                            # assert not relion_category_dict['chunk'][idx_is_category_found]
                            for i_sphire_rebox_entry in range(n_sphire_rebox_entry):
                                sphire_chunk_id_list.append(dummy_sphire_chunk_id)
                        assert n_sphire_rebox_entry == len(sphire_chunk_id_list)

                        # Standard SPA Coordinate File
                        for i_sphire_rebox_entry in range(n_sphire_rebox_entry):
                            line = ""
                            line += " {:6d}".format(
                                sphire_coordinates_list[i_sphire_rebox_entry][
                                    idx_ptcl_source_coord_id
                                ]
                            )  # idx_params_mic_coord_id
                            # in star file they are floats, so they have to be properly rounded,  PAP
                            line += " {:6d}".format(
                                int(
                                    round(
                                        sphire_coordinates_list[i_sphire_rebox_entry][
                                            idx_ptcl_source_coord_x
                                        ]
                                    )
                                )
                            )  # idx_params_mic_coord_x
                            line += " {:6d}".format(
                                int(
                                    round(
                                        sphire_coordinates_list[i_sphire_rebox_entry][
                                            idx_ptcl_source_coord_y
                                        ]
                                    )
                                )
                            )  # idx_params_mic_coord_y
                            line += " {:13.6f}".format(
                                sphire_coordinates_list[i_sphire_rebox_entry][
                                    idx_ptcl_source_resample_ratio
                                ]
                            )  # idx_params_mic_resample_ratio
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_def]
                            )  # idx_params_ctf_defocus
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_cs]
                            )  # idx_params_ctf_cs
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_vol]
                            )  # idx_params_ctf_voltage
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_apix]
                            )  # idx_params_ctf_apix
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_bfactor]
                            )  # idx_params_ctf_bfactor
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][idx_cter_total_ac]
                            )  # idx_params_ctf_ampcont
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][
                                    idx_cter_astig_amp
                                ]
                            )  # idx_params_ctf_dfdiff
                            line += " {:13.6f}".format(
                                sphire_ctf_list[i_sphire_rebox_entry][
                                    idx_cter_astig_ang
                                ]
                            )  # idx_params_ctf_dfang
                            line += " {:13.6f}".format(
                                sphire_proj3d_list[i_sphire_rebox_entry]["phi"]
                            )  # idx_params_proj_phi
                            line += " {:13.6f}".format(
                                sphire_proj3d_list[i_sphire_rebox_entry]["theta"]
                            )  # idx_params_proj_theta
                            line += " {:13.6f}".format(
                                sphire_proj3d_list[i_sphire_rebox_entry]["psi"]
                            )  # idx_params_proj_psi
                            line += " {:13.6f}".format(
                                sphire_proj3d_list[i_sphire_rebox_entry]["tx"]
                            )  # idx_params_proj_sx
                            line += " {:13.6f}".format(
                                sphire_proj3d_list[i_sphire_rebox_entry]["ty"]
                            )  # idx_params_proj_sy
                            line += " {:13.6f}".format(
                                dummy_particle_defocus_error
                            )  # idx_params_defocus_error
                            line += " {:15.6f}".format(
                                dummy_particle_resample_ratio
                            )  # idx_params_resample_ratio
                            line += " {:6d}".format(
                                sphire_chunk_id_list[i_sphire_rebox_entry]
                            )  # idx_params_chunk_id NOT SUPPORTED YET (Toshio Moriya 2018/07/10)
                            line += " \n"

                            file_rebox.write(line)

                        file_rebox.close()
            else:
                # assert relion_category_dict['window'][idx_is_category_found]
                # Write rebox parameters to files (doing here to avoid repeating open/close files in loop)
                sp_global_def.sxprint("# ")
                sp_global_def.sxprint(
                    "# Particle coodinates are not found! Skipping save SPHIRE rebox files ..."
                )
        else:
            # assert relion_category_dict['helical'][idx_is_category_found]:
            sp_global_def.sxprint("# ")
            sp_global_def.sxprint(
                "# For helical reconstruction, SPHIRE rebox files are not supported yet ..."
            )
            sp_global_def.sxprint("# Skipping save SPHIRE rebox files ...")

        if is_enable_create_stack:
            assert relion_category_dict["window"][idx_is_category_found], "MRK_DEBUG"

            sp_global_def.sxprint("# ")
            sp_global_def.sxprint(
                "# Creating local particle stack for each micrograph..."
            )

            for micrograph_dirname in sorted(sphire_header_dict):
                sp_global_def.sxprint("# ")
                sp_global_def.sxprint(
                    "# Processing {} directory ...".format(micrograph_dirname)
                )

                dir_path_local_bdb_stacks = os.path.join(
                    dir_path_work,
                    os.path.join(
                        *[
                            entry
                            for entry in micrograph_dirname.split("/")
                            if entry != ".."
                        ]
                    ),
                    dir_name_local_stacks,
                )
                if not os.path.exists(dir_path_local_bdb_stacks):
                    os.makedirs(dir_path_local_bdb_stacks)

                for i_micrograph, micrograph_basename in enumerate(
                    sorted(sphire_header_dict[micrograph_dirname])
                ):
                    if i_micrograph % 100 == 0:
                        sp_global_def.sxprint(
                            "# Processing micrographs from {:5d} to {:5d} in {} directory...".format(
                                i_micrograph, i_micrograph + 100 - 1, micrograph_dirname
                            )
                        )

                    micrograph_baseroot = os.path.splitext(micrograph_basename)[0]
                    file_path_local_bdb_stack = "bdb:{}#{}_ptcls".format(
                        dir_path_local_bdb_stacks, micrograph_baseroot
                    )
                    local_bdb_stack = EMAN2db.db_open_dict(file_path_local_bdb_stack)

                    for sphire_header_id, sphire_header in enumerate(
                        sphire_header_dict[micrograph_dirname][micrograph_basename]
                    ):
                        # Copy this particle image from local stack to new global stack
                        # First read image
                        relion_local_stack_path = sphire_header[
                            "relion_local_stack_path"
                        ]
                        sphire_local_particle_id = sphire_header[
                            "sphire_local_particle_id"
                        ]
                        assert os.path.exists(relion_local_stack_path)
                        n_img_relion_local_stack = EMAN2_cppwrap.EMUtil.get_image_count(
                            relion_local_stack_path
                        )
                        assert (
                            sphire_local_particle_id < n_img_relion_local_stack
                        ), "# Logical Error: The local particle ID must not exceed the number of images in the assocaited local particle stack."
                        img_particle = sp_utilities.get_im(
                            relion_local_stack_path, sphire_local_particle_id
                        )
                        img_particles_dict = img_particle.get_attr_dict()

                        # NOTE: 2015/10/19 Toshio Moriya
                        # Store the extracted information into the image header
                        img_particles_dict["ptcl_source_relion"] = sphire_header[
                            "ptcl_source_relion"
                        ]
                        img_particles_dict["ptcl_source_image"] = sphire_header[
                            "ptcl_source_image"
                        ]
                        img_particles_dict["ptcl_source_coord"] = sphire_header[
                            "ptcl_source_coord"
                        ]  # No conversion is necessary from RELION to SPHIRE formats
                        img_particles_dict["ptcl_source_coord_id"] = sphire_header[
                            "ptcl_source_coord_id"
                        ]
                        img_particles_dict["data_n"] = sphire_header[
                            "data_n"
                        ]  # NOTE: Toshio Moriya 2017/11/20: same as ptcl_source_coord_id but the other program uses this header entry key...
                        img_particles_dict["data_path"] = makerelpath(
                            dir_path_local_bdb_stacks + "/EMAN2DB",
                            relion_local_stack_path,
                        )  # NOTE: Markus Stabrin 2018/09/17: Link to existing mrcs stack
                        img_particles_dict["resample_ratio"] = sphire_header[
                            "resample_ratio"
                        ]
                        #
                        # NOTE: 2017/12/05 Toshio Moriya
                        # Add header entries so that it consistent with sxwindow.py (refer note in sxwindow.py about why these are set to 1.0[A])
                        #
                        img_particles_dict["apix_x"] = sphire_header["apix_x"]
                        img_particles_dict["apix_y"] = sphire_header["apix_y"]
                        img_particles_dict["apix_z"] = sphire_header["apix_z"]

                        if (
                            relion_category_dict["helical"][idx_is_category_found]
                            == True
                        ):
                            img_particles_dict["filament_id"] = sphire_header[
                                "filament_id"
                            ]
                            img_particles_dict["segment_id"] = sphire_header[
                                "segment_id"
                            ]
                            img_particles_dict["filament_track_length"] = sphire_header[
                                "filament_track_length"
                            ]
                            if sphire_header["segment_angle"] is None:
                                if sphire_header_id != 0:
                                    prev = sphire_header_dict[micrograph_dirname][
                                        micrograph_basename
                                    ][sphire_header_id - 1]
                                else:
                                    prev = None
                                try:
                                    nexti = sphire_header_dict[micrograph_dirname][
                                        micrograph_basename
                                    ][sphire_header_id + 1]
                                except IndexError:
                                    nexti = None
                                if prev is None and nexti is None:
                                    angle = 0
                                elif (
                                    prev is None
                                    and sphire_header["filament_id"]
                                    == nexti["filament_id"]
                                ):
                                    angle = estimate_angle(
                                        sphire_header["ptcl_source_coord"],
                                        nexti["ptcl_source_coord"],
                                    )
                                elif (
                                    nexti is None
                                    and sphire_header["filament_id"]
                                    == prev["filament_id"]
                                ):
                                    angle = estimate_angle(
                                        prev["ptcl_source_coord"],
                                        sphire_header["ptcl_source_coord"],
                                    )
                                elif (
                                    prev["filament_id"] == sphire_header["filament_id"]
                                    and sphire_header["filament_id"]
                                    != nexti["filament_id"]
                                ):
                                    angle = estimate_angle(
                                        prev["ptcl_source_coord"],
                                        sphire_header["ptcl_source_coord"],
                                    )
                                elif (
                                    prev["filament_id"] != sphire_header["filament_id"]
                                    and sphire_header["filament_id"]
                                    == nexti["filament_id"]
                                ):
                                    angle = estimate_angle(
                                        sphire_header["ptcl_source_coord"],
                                        nexti["ptcl_source_coord"],
                                    )
                                elif (
                                    prev["filament_id"] == sphire_header["filament_id"]
                                    and sphire_header["filament_id"]
                                    == nexti["filament_id"]
                                ):
                                    angle = estimate_angle(
                                        prev["ptcl_source_coord"],
                                        nexti["ptcl_source_coord"],
                                    )
                                else:
                                    raise Exception(
                                        "This part of the code should not be reached!"
                                    )
                                img_particles_dict["segment_angle"] = angle
                            else:
                                img_particles_dict["segment_angle"] = sphire_header[
                                    "segment_angle"
                                ]
                        if (
                            relion_category_dict["ctf"][idx_is_category_found] == True
                            or options.negative_stain
                        ):
                            img_particles_dict["ctf"] = sphire_header["ctf"]
                            img_particles_dict["ctf_applied"] = sphire_header[
                                "ctf_applied"
                            ]
                            img_particles_dict["ptcl_source_apix"] = sphire_header[
                                "ptcl_source_apix"
                            ]  # Store the original pixel size
                        if (
                            relion_category_dict["proj3d"][idx_is_category_found]
                            == True
                        ):
                            sp_utilities.set_params_proj(
                                img_particle, sphire_header["xform.projection"]
                            )
                            img_particles_dict[
                                "xform.projection"
                            ] = img_particle.get_attr("xform.projection")
                            # Add relion specific header entries
                            img_particles_dict["relion_max_prob_dist"] = sphire_header[
                                "relion_max_prob_dist"
                            ]
                            img_particles_dict["relion_norm_correct"] = sphire_header[
                                "relion_norm_correct"
                            ]
                        if relion_category_dict["chunk"][idx_is_category_found] == True:
                            img_particles_dict["chunk_id"] = sphire_header["chunk_id"]

                        # Write the particle image to local stack file
                        local_bdb_stack[sphire_header_id] = img_particles_dict
                    EMAN2db.db_close_dict(file_path_local_bdb_stack)

                # # NOTE: Toshio Moriya 2018/07/09
                # # Unfortunately, the following method does not work maybe because of synchronization problem of subprocess...
                # file_path_sphire_mic_dir_stack = 'bdb:{}#{}_stack'.format(os.path.join(dir_path_work, micrograph_dirname), outputs_root)
                # e2bdb_command = 'e2bdb.py  {}  --makevstack={}'.format(dir_path_local_bdb_stacks, file_path_sphire_mic_dir_stack)
                # sxprint('# ')
                # sxprint('# Putting local stacks together to a virtual stack...')
                # sxprint('#  {}'.format(e2bdb_command))
                # # cmdexecute(e2bdb_command, printing_on_success = False)
                # cmdexecute(e2bdb_command)
                #
                # assert db_check_dict(file_path_sphire_mic_dir_stack, readonly=True), '# Logical Error: Output BDB stack in output directory should exist at this point of code.'
                # assert i_sphire_stack_particle_img == EMUtil.get_image_count(file_path_sphire_mic_dir_stack), '# The numbers of particles should match always at this point of code'

                file_path_sphire_mic_dir_stack = "bdb:{}#{}_stack".format(
                    dir_path_local_bdb_stacks, outputs_root
                )
                e2bdb_command = "e2bdb.py  {}  --makevstack={}".format(
                    dir_path_local_bdb_stacks, file_path_sphire_mic_dir_stack
                )
                sp_global_def.sxprint("# ")
                sp_global_def.sxprint(
                    "# Please execute the following command line to create single virtual stack by combining all local stacks in {} directory".format(
                        micrograph_dirname
                    )
                )
                sp_global_def.sxprint("#   {}".format(e2bdb_command))

            # # NOTE: Toshio Moriya 2018/07/10
            # # Unfortunately, the following method does not work maybe because of synchronization problem of subprocess...
            # if not cs_save_as_hdf:
            # 	is_not_first = False
            # 	for micrograph_dirname in sorted(sphire_header_dict):
            # 		dir_path_local_bdb_stacks = os.path.join(dir_path_work, micrograph_dirname, dir_name_local_stacks)
            # 		try:
            # 			os.mkdir(dir_path_local_bdb_stacks)
            # 			assert False, "MRK_DEBUG: Unreachable code..."
            # 		except OSError as err:
            # 			pass
            #
            # 		file_path_bdb_stack = 'bdb:{}#{}_stack'.format(dir_path_work, outputs_root)
            # 		e2bdb_command = 'e2bdb.py  {}  --makevstack={}'.format(dir_path_local_bdb_stacks, file_path_bdb_stack)
            # 		sxprint('# ')
            # 		sxprint('# Creating single virtual stack by combining all local stacks together...')
            # 		sxprint('#  {}'.format(e2bdb_command))
            # 		# cmdexecute(e2bdb_command, printing_on_success = False)
            # 		cmdexecute(e2bdb_command)
            #
            # 		assert db_check_dict(file_path_bdb_stack, readonly=True), '# Logical Error: Output BDB stack in output directory should exist at this point of code.'
            # 		assert i_sphire_stack_particle_img == EMUtil.get_image_count(file_path_bdb_stack), '# The numbers of particles should match always at this point of code'
            # # else:
            # # 	# assert cs_save_as_hdf
            # # 	# Do nothing

        # # Write chunk parameter files (particle id list of each chunk/group) parameter files
        # for sphire_chunk_key in sphire_chunk_dict:
        # 	# Open the files for this chunk key
        # 	file_name_sphire_stack_chunk = name_pattern_sphire_stack_chunk.replace('*', sphire_chunk_key)
        # 	file_path_sphire_stack_chunk = dir_path_work + '/' + file_name_sphire_stack_chunk
        # 	file_sphire_stack_chunk = open(file_path_sphire_stack_chunk, 'w+')
        # 	# Write the list of particle IDs of each chunk
        # 	for relion_particle_id in sphire_chunk_dict[sphire_chunk_key]:
        # 		file_sphire_stack_chunk.write('%d \n' % (relion_particle_id))
        # 	# Close the files for this chunk key
        # 	file_sphire_stack_chunk.close()

    # Close input/output files
    file_relion_star.close()

    sp_global_def.sxprint("# ")
    sp_global_def.sxprint("# DONE!")


def main():
    sp_global_def.print_timestamp("Start")
    run()
    sp_global_def.print_timestamp("Finish")

# ----------------------------------------------------------------------------------------

if __name__ == "__main__":
    main()

# ========================================================================================
# END OF SCRIPT
# ========================================================================================
