diff --git a/shapelets/core/analysis.py b/shapelets/core/analysis.py
new file mode 100644
index 0000000..bda351c
--- /dev/null
+++ b/shapelets/core/analysis.py
@@ -0,0 +1,111 @@
+########################################################################################################################
+# Copyright 2023 the authors (see AUTHORS file for full list). #
+# #
+# This file is part of shapelets. #
+# #
+# Shapelets is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General #
+# Public License as published by the Free Software Foundation, either version 2.1 of the License, or (at your option) #
+# any later version. #
+# #
+# Shapelets 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 Lesser General Public License for more #
+# details. #
+# #
+# You should have received a copy of the GNU Lesser General Public License along with shapelets. If not, see #
+# . #
+########################################################################################################################
+
+import ast
+import configparser
+import os
+import sys
+
+from ..astronomy.galaxy import decompose_galaxies, get_postage_stamps, load_fits_data
+
+from ..self_assembly.misc import process_output, read_image
+from ..self_assembly.quant import defectid, orientation, rdistance
+
+METHODS_ASTRONOMY = ['galaxy_decompose']
+METHODS_SELFASSEMBLY = ['response_distance', 'orientation', 'identify_defects']
+
+def do_analysis(config: configparser.ConfigParser, working_dir: str, image_dir: str, output_dir: str) -> None:
+ r"""
+ Main function that handles usage of the configuration file method by appropriately directing the parameters in the config file for the requested analysis.
+
+ Parameters
+ ----------
+ * config : configparser.ConfigParser
+ * The parsed configuration file
+ * working_dir : str
+ * The absolute path (working directory) where the entry point was invoked from
+ * image_dir : str
+ * The directory containing the image (or .FITS file) for analysis
+ * output_dir : str
+ * The output directory where results from the analysis will be saved
+
+ """
+ method = config.get('general', 'method')
+
+ # shapelets.astronomy submodule #
+ # ----------------------------- #
+
+ # galaxy decomposition: https://doi.org/10.1046/j.1365-8711.2003.05901.x
+ if method == 'galaxy_decompose':
+ fits_name = config.get('general', 'fits_name')
+ fits_path = os.path.join(working_dir, 'images', fits_name)
+
+ shapelet_order = config.get('galaxy_decompose', 'shapelet_order', fallback = 'default')
+ compression_order = config.get('galaxy_decompose', 'compression_order', fallback = 'default')
+
+ output_base_path = output_dir+fits_path[fits_path.rfind('/'):-5]
+ n_max = int([shapelet_order, 10][shapelet_order == 'default'])
+ compression_factor = int([compression_order, 25][compression_order == 'default'])
+
+ fits_data = load_fits_data(fits_path)
+ (galaxy_stamps, star_stamps, noiseless_data) = get_postage_stamps(fits_data, output_base_path)
+ decompose_galaxies(galaxy_stamps, star_stamps, noiseless_data, n_max, compression_factor, output_base_path)
+
+ sys.exit()
+
+
+ # shapelets.self_assembly #
+ # ----------------------- #
+
+ image_name = config.get('general', 'image_name')
+ image = read_image(image_name = image_name, image_path = image_dir)
+
+ # response distance: https://doi.org/10.1088/1361-6528/ad1df4
+ if method == 'response_distance':
+ shapelet_order = config.get('response_distance', 'shapelet_order', fallback = 'default')
+ if shapelet_order != 'default':
+ shapelet_order = ast.literal_eval(shapelet_order)
+
+ num_clusters = config.get('response_distance', 'num_clusters', fallback = 20)
+ num_clusters = ast.literal_eval(num_clusters)
+
+ ux = config.get('response_distance', 'ux', fallback = 'default')
+ uy = config.get('response_distance', 'uy', fallback = 'default')
+ if ux != 'default':
+ ux = ast.literal_eval(ux)
+ if uy != 'default':
+ uy = ast.literal_eval(uy)
+
+ rd_field = rdistance(image = image, num_clusters = num_clusters, shapelet_order = shapelet_order, ux = ux, uy = uy)
+
+ process_output(image = image, image_name = image_name, save_path = output_dir, output_from = 'response_distance', d = rd_field, num_clusters = num_clusters)
+
+ # local pattern orientation: https://doi.org/10.1088/1361-6528/ad1df4
+ elif method == 'orientation':
+ pattern_order = config.get('orientation', 'pattern_order')
+
+ mask, dilate, blended, maxval = orientation(image = image, pattern_order = pattern_order)
+
+ process_output(image = image, image_name = image_name, save_path = output_dir, output_from = 'orientation', mask = mask, dilate = dilate, orientation = blended, maxval = maxval)
+
+ # defect identification method: https://doi.org/10.1088/1361-6528/ad1df4
+ elif method == 'identify_defects':
+ pattern_order = config.get('identify_defects', 'pattern_order')
+
+ centroids, clusterMembers, defects = defectid(image = image, pattern_order = pattern_order)
+
+ process_output(image = image, image_name = image_name, save_path = output_dir, output_from = 'identify_defects', centroids = centroids, clusterMembers = clusterMembers, defects = defects)
\ No newline at end of file
diff --git a/shapelets/core/run.py b/shapelets/core/run.py
index 8377042..9e08ab0 100644
--- a/shapelets/core/run.py
+++ b/shapelets/core/run.py
@@ -15,19 +15,14 @@
# . #
########################################################################################################################
-import ast
import configparser
import os
-from ..astronomy.galaxy import *
-
-from ..self_assembly.misc import *
-from ..self_assembly.quant import *
-from ..self_assembly.wavelength import *
+from .analysis import do_analysis, METHODS_ASTRONOMY, METHODS_SELFASSEMBLY
def run(config_file: str, working_dir: str) -> None:
r"""
- Main run function that handles input configuration file.
+ Main run function that parses the configuration file, ensures it exists in the provided (working) directory, and sets up output directory for post-analysis.
Parameters
----------
@@ -35,92 +30,28 @@ def run(config_file: str, working_dir: str) -> None:
* The name of the configuration file in working_dir
* working_dir : str
* The absolute path (working directory) where the entry point was invoked from
-
- Notes
- -----
- Differentiation between submodule use is based on image_name or fits_name provided in config file. Note that this may need to be changed in the future if more astronomy functionality is added.
"""
config = configparser.ConfigParser()
- config_file = os.path.join(working_dir, config_file)
- if not os.path.exists(config_file):
- raise RuntimeError(f"Configuration file {config_file} does not exist. Check config filename spelling and ensure that it is located in {working_dir}.")
- else:
- config.read(config_file)
-
- method = config.get('general', 'method')
-
- image_path = os.path.join(working_dir, 'images')
- save_path = os.path.join(working_dir, 'output')
- if not os.path.exists(image_path):
- raise RuntimeError(f"Path '{image_path}' does not exist.")
- if not os.path.exists(save_path):
- os.mkdir(save_path)
-
- ## self_assembly submodule use ##
-
- # parsing input image of nanostructure
- if config.get('general', 'image_name', fallback=None):
-
- # read image to be analyzed
- image_name = config.get('general', 'image_name')
- image = read_image(image_name = image_name, image_path = image_path)
-
- if method == 'response_distance':
- shapelet_order = config.get('response_distance', 'shapelet_order', fallback = 'default')
- if shapelet_order != 'default':
- shapelet_order = ast.literal_eval(shapelet_order)
-
- num_clusters = config.get('response_distance', 'num_clusters', fallback = 20)
- num_clusters = ast.literal_eval(num_clusters)
-
- ux = config.get('response_distance', 'ux', fallback = 'default')
- uy = config.get('response_distance', 'uy', fallback = 'default')
- if ux != 'default':
- ux = ast.literal_eval(ux)
- if uy != 'default':
- uy = ast.literal_eval(uy)
- rd_field = rdistance(image = image, num_clusters = num_clusters, shapelet_order = shapelet_order, ux = ux, uy = uy)
-
- process_output(image = image, image_name = image_name, save_path = save_path, output_from = 'response_distance', d = rd_field, num_clusters = num_clusters)
-
- elif method == 'orientation':
- pattern_order = config.get('orientation', 'pattern_order')
-
- mask, dilate, blended, maxval = orientation(image = image, pattern_order = pattern_order)
-
- process_output(image = image, image_name = image_name, save_path = save_path, output_from = 'orientation', mask = mask, dilate = dilate, orientation = blended, maxval = maxval)
-
- elif method == 'identify_defects':
- pattern_order = config.get('identify_defects', 'pattern_order')
-
- centroids, clusterMembers, defects = defectid(image = image, pattern_order = pattern_order)
-
- process_output(image = image, image_name = image_name, save_path = save_path, output_from = 'identify_defects', centroids = centroids, clusterMembers = clusterMembers, defects = defects)
+ config_file = os.path.join(working_dir, config_file)
- else:
- raise ValueError("method parameter {method} from configuration file not recognized by shapelets.")
+ if not os.path.exists(config_file):
+ raise RuntimeError(f"Configuration file {config_file} does not exist. Check filename spelling and ensure it is located in {working_dir}.")
- ## astronomy submodule use ##
-
- # retrieving .fits path (if .fits file is provided)
- elif config.get('general', 'fits_name', fallback=None):
- fits_path = os.path.join(working_dir, 'images', config.get('general', 'fits_name'))
+ config.read(config_file)
- if method == 'galaxy_decompose':
- shapelet_order = config.get('galaxy_decompose', 'shapelet_order', fallback = 'default')
- compression_order = config.get('galaxy_decompose', 'compression_order', fallback = 'default')
+ all_methods = METHODS_ASTRONOMY + METHODS_SELFASSEMBLY
- output_base_path = save_path+fits_path[fits_path.rfind('/'):-5]
- n_max = int([shapelet_order, 10][shapelet_order == 'default'])
- compression_factor = int([compression_order, 25][compression_order == 'default'])
+ if config.get('general', 'method') not in all_methods:
+ raise RuntimeError(f"The method '{config.get('general', 'method')}' provided in configuration file '{config_file}' is not recognized by shapelets. Available options are: {', '.join(m for m in all_methods)}.")
+
+ image_dir = os.path.join(working_dir, 'images')
+ if not os.path.exists(image_dir):
+ raise RuntimeError(f"Path '{image_dir}' does not exist.")
+
+ output_dir = os.path.join(working_dir, 'output')
+ if not os.path.exists(output_dir):
+ os.mkdir(output_dir)
- fits_data = load_fits_data(fits_path)
- (galaxy_stamps, star_stamps, noiseless_data) = get_postage_stamps(fits_data, output_base_path)
- decompose_galaxies(galaxy_stamps, star_stamps, noiseless_data, n_max, compression_factor, output_base_path)
- else:
- raise ValueError("method parameter {method} from configuration file not recognized by shapelets.")
-
- else:
- raise NameError("No image (from image_name) or FITS (from fits_name) listed in configuration file.")
\ No newline at end of file
+ do_analysis(config, working_dir, image_dir, output_dir)
\ No newline at end of file