Пример #1
0
    def generate_paths(self):
        """
        Initialise the file structure
        """

        # Output subdirectory to structure results from APM analyses
        output_subdir = f"/{self.project_basename}" + "_{counter:03d}"

        # ===== Directories =====
        self.paths = ProjectPaths(self.project_dir)
        self.paths.add_path(uid='d_aircraft', path=PATHS.DIR.AIRCRAFT, uid_groups='dir')
        self.paths.add_path(uid='d_airfoils', path=PATHS.DIR.AIRFOILS, uid_groups='dir')
        self.paths.add_path(uid='d_deformation', path=PATHS.DIR.DEFORMATION, uid_groups='dir')
        self.paths.add_path(uid='d_settings', path=PATHS.DIR.SETTINGS, uid_groups='dir')
        self.paths.add_path(uid='d_state', path=PATHS.DIR.STATE, uid_groups='dir')
        # Output directories
        self.paths.add_path(uid='d_plots_TOP', path=PATHS.DIR.PLOTS, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_results_TOP', path=PATHS.DIR.RESULTS, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_plots', path=PATHS.DIR.PLOTS+output_subdir, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_results', path=PATHS.DIR.RESULTS+output_subdir, uid_groups=('dir', 'tmp'))

        # ===== Files =====
        self.paths.add_path(uid='f_log', path=PATHS.FILES.LOG)
        self.paths.add_subpath(uid_parent='d_aircraft', uid='f_aircraft', path=f"{self.settings['aircraft']}")
        self.paths.add_subpath(uid_parent='d_deformation', uid='f_deformation', path=f"{self.settings['deformation']}")
        self.paths.add_subpath(uid_parent='d_settings', uid='f_settings', path=f"{self.project_basename}.json")
        self.paths.add_subpath(uid_parent='d_state', uid='f_state', path=f"{self.settings['state']}")
        # Output files
        self.paths.add_subpath(uid_parent='d_results', uid='f_results_global', path=f"global.json")  # File namespaced with folder
        self.paths.add_subpath(uid_parent='d_results', uid='f_results_panelwise', path=f"panelwise.dat")  # File namespaced with folder
        self.paths.add_subpath(uid_parent='d_results_TOP', uid='f_results_apm_global', path=f"{self.project_basename}_aeroperformance.json")
Пример #2
0
def test_calling_paths():
    """
    Test calling functions
    """

    paths = ProjectPaths(ROOT)

    paths.add_path(uid=UID1, path=PATH1, uid_groups=UID_GROUP1)
    assert str(paths(UID1)).endswith(f'/{ROOT}/{PATH1}')
Пример #3
0
def test_counter_paths():
    """
    Test counter paths
    """

    paths = ProjectPaths(ROOT)
    assert paths.counter == 0

    # Setting
    invalid_conter_values = [1.2, '23', None]

    for invalid_conter_value in invalid_conter_values:
        with raises(ValueError):
            paths.counter = invalid_conter_value

    paths.counter = 1  # Value okay
Пример #4
0
def test_project_paths_basics():
    """
    Test basics
    """

    paths = ProjectPaths(ROOT)
    assert str(paths.root.name) == ROOT
    assert paths.root == paths(ProjectPaths.UID_ROOT)
Пример #5
0
    def __init__(self, root_dir=None, make_dirs=True):
        """
        Aeroframe file structure

        Note:
            * If 'root_dir' is None, the root directory, we use 'os.getcwd()'

        Args:
            :root_dir: (str,path) Project root folder
            :make_dirs: (bool) If True, make directories of group 'init'
        """

        if root_dir is None:
            root_dir = os.getcwd()

# ==============================
        self.settings = None

        self.cfd_wrapper = None
        self.stru_wrapper = None
# ==============================

        self.paths = ProjectPaths(root_dir)

        # ----- Directories -----
        self.paths.add_path(
            uid='d_cfd',
            path=PATHS.DIRS.CFD,
            uid_groups=(PATHS.GROUPS.INIT, PATHS.GROUPS.CFD)
        )

        self.paths.add_path(
            uid='d_structure',
            path=PATHS.DIRS.STRUCTURE,
            uid_groups=(PATHS.GROUPS.INIT, PATHS.GROUPS.STRUCTURE)
        )

        # ----- Files -----
        self.paths.add_path(
            uid='f_root_settings',
            path=PATHS.FILES.DEFAULT_SETTINGS
        )

        if make_dirs:
            self.init_dirs()
Пример #6
0
def test_mk_rm_dirs():
    """
    Test making/remove directories
    """

    paths = ProjectPaths(ROOT)

    paths.add_path(uid=UID1, path=PATH1, uid_groups=UID_GROUP1)
    paths.add_path(uid=UID2, path=PATH2, uid_groups=UID_GROUP1)
    paths.make_dirs_for_groups(UID_GROUP1, is_dir=True)
    assert os.path.exists(paths(UID1))
    assert os.path.exists(paths(UID2))

    paths.rm_dirs_for_groups(UID_GROUP1)
    assert not os.path.exists(paths(UID1))
    assert not os.path.exists(paths(UID2))
Пример #7
0
class Settings:

    def __init__(self, root_dir=None, make_dirs=True):
        """
        Aeroframe file structure

        Note:
            * If 'root_dir' is None, the root directory, we use 'os.getcwd()'

        Args:
            :root_dir: (str,path) Project root folder
            :make_dirs: (bool) If True, make directories of group 'init'
        """

        if root_dir is None:
            root_dir = os.getcwd()

# ==============================
        self.settings = None

        self.cfd_wrapper = None
        self.stru_wrapper = None
# ==============================

        self.paths = ProjectPaths(root_dir)

        # ----- Directories -----
        self.paths.add_path(
            uid='d_cfd',
            path=PATHS.DIRS.CFD,
            uid_groups=(PATHS.GROUPS.INIT, PATHS.GROUPS.CFD)
        )

        self.paths.add_path(
            uid='d_structure',
            path=PATHS.DIRS.STRUCTURE,
            uid_groups=(PATHS.GROUPS.INIT, PATHS.GROUPS.STRUCTURE)
        )

        # ----- Files -----
        self.paths.add_path(
            uid='f_root_settings',
            path=PATHS.FILES.DEFAULT_SETTINGS
        )

        if make_dirs:
            self.init_dirs()

    def init_dirs(self):
        """
        Create directories belonging to 'init' group
        """

        self.paths.make_dirs_for_groups(uid_groups='init', is_dir=True)

    def init_emtpy_settings_file(self, overwrite=False):
        """
        Create a settings file with default values

        Args:
            :overwrite: (bool) If True, overwrite an existing settings file
        """

        settings_file = self.paths("f_root_settings")

        if not overwrite and settings_file.exists():
            raise FileExistsError(f"Path '{settings_file}' exists. Will not overwrite.")

        with open(settings_file, "w") as fp:
            settings_dict = get_default_value_dict(DEFAULT_SETTINGS_DICT)
            dump_pretty_json(settings_dict, fp)

# ==============================
# ==============================
    def load_root_settings(self):
        """
        Load and return the root settings file

        Args:
            :aeroframe_files: file structure of aeroframe program
        """

        with open(self.paths("f_root_settings"), "r") as fp:
            self.settings = json.load(fp)

    def get_wrappers(self):
        """
        Load wrapper modules dynamically

        Args:
            :aeroframe_files: file structure of aeroframe program
        """

        self.load_root_settings()

        self.cfd_lib = importlib.import_module(self.settings['cfd_model']['wrapper'])
        self.stru_lib = importlib.import_module(self.settings['structure_model']['wrapper'])

        root_path = root_path = self.paths('root')
        cfd_settings = self.settings['cfd_model'].get('exec_settings', {})
        stru_settings = self.settings['structure_model'].get('exec_settings', {})

        # Wrapper must share same instance of 'SharedData()'
        shared_data = SharedData()
        cfd_wrapper = self.cfd_lib.Wrapper(root_path, shared_data, cfd_settings)
        stru_wrapper = self.stru_lib.Wrapper(root_path, shared_data, stru_settings)
        return cfd_wrapper, stru_wrapper
Пример #8
0
class Settings:

    def __init__(self, settings_filename, project_dir, *,
                 settings_dict=None, make_dirs=True, check_ac_file_type=True):
        """
        Data structure with PyTornado execution settings

        Attributes:
            :settings_filename: Name of the settings file
            :project_dir: PyTornado project directory (where all data is expected)
            :settings_dict: Basic settings data as a dictionary
            :make_dirs: (bool) Flag for creation of project directories
        """

        self.project_dir = Path(project_dir).resolve()
        self.project_basename = os.path.splitext(settings_filename)[0]
        self.settings = get_default_dict(template_dict=DEFAULT_SETTINGS)

        if settings_dict is not None:
            self.update_from_dict(settings_dict)

        self.paths = None
        self.generate_paths()

        # Aircraft format
        self.aircraft_is_cpacs = None
        if check_ac_file_type:
            self._check_aircraft_file_type()

        if make_dirs:
            self.paths.make_dirs_for_groups('dir')

    @property
    def state_is_cpacs(self):
        """
        Flag indicating if state is to be read from CPACS
        """

        if self.settings['state'].upper() == '__CPACS':
            if not self.aircraft_is_cpacs:
                raise RuntimeError("State cannot be read from CPACS if aircraft file is not CPACS")
            return True
        else:
            return False

    def generate_paths(self):
        """
        Initialise the file structure
        """

        # Output subdirectory to structure results from APM analyses
        output_subdir = f"/{self.project_basename}" + "_{counter:03d}"

        # ===== Directories =====
        self.paths = ProjectPaths(self.project_dir)
        self.paths.add_path(uid='d_aircraft', path=PATHS.DIR.AIRCRAFT, uid_groups='dir')
        self.paths.add_path(uid='d_airfoils', path=PATHS.DIR.AIRFOILS, uid_groups='dir')
        self.paths.add_path(uid='d_deformation', path=PATHS.DIR.DEFORMATION, uid_groups='dir')
        self.paths.add_path(uid='d_settings', path=PATHS.DIR.SETTINGS, uid_groups='dir')
        self.paths.add_path(uid='d_state', path=PATHS.DIR.STATE, uid_groups='dir')
        # Output directories
        self.paths.add_path(uid='d_plots_TOP', path=PATHS.DIR.PLOTS, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_results_TOP', path=PATHS.DIR.RESULTS, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_plots', path=PATHS.DIR.PLOTS+output_subdir, uid_groups=('dir', 'tmp'))
        self.paths.add_path(uid='d_results', path=PATHS.DIR.RESULTS+output_subdir, uid_groups=('dir', 'tmp'))

        # ===== Files =====
        self.paths.add_path(uid='f_log', path=PATHS.FILES.LOG)
        self.paths.add_subpath(uid_parent='d_aircraft', uid='f_aircraft', path=f"{self.settings['aircraft']}")
        self.paths.add_subpath(uid_parent='d_deformation', uid='f_deformation', path=f"{self.settings['deformation']}")
        self.paths.add_subpath(uid_parent='d_settings', uid='f_settings', path=f"{self.project_basename}.json")
        self.paths.add_subpath(uid_parent='d_state', uid='f_state', path=f"{self.settings['state']}")
        # Output files
        self.paths.add_subpath(uid_parent='d_results', uid='f_results_global', path=f"global.json")  # File namespaced with folder
        self.paths.add_subpath(uid_parent='d_results', uid='f_results_panelwise', path=f"panelwise.dat")  # File namespaced with folder
        self.paths.add_subpath(uid_parent='d_results_TOP', uid='f_results_apm_global', path=f"{self.project_basename}_aeroperformance.json")

    def _check_aircraft_file_type(self):
        """Check whether aircraft is a CPACS or a JSON file"""

        ac_file_extension = self.paths('f_aircraft').suffix.lower()

        if ac_file_extension not in ['.xml', '.json']:
            raise ValueError("Aircraft file must have extension '.json' or '.xml' (CPACS)")

        if ac_file_extension == '.json':
            self.aircraft_is_cpacs = False
        else:
            self.aircraft_is_cpacs = True

    def update_from_dict(self, settings_dict):
        """
        Update settings from dictionary structures

        Args:
            :settings: Dictionary with general settings
            :plot: Dictionary with plot settings
        """

        for key, value in settings_dict.items():
            self.settings[key] = value

        # If 'results' are not specified, plot 'cp' values
        if not self.settings['plot']['results']['opt']:
            self.settings['plot']['results']['opt'] = ['cp']

        self._check_settings_dict()

    def clean(self):
        """
        Remove old files in project directory
        """

        self.paths.rm_dirs_for_groups('tmp')

    def _check_settings_dict(self):
        """
        Check that settings dictionary contains valid input arguments
        """

        logger.debug("Checking settings...")
        check_dict(template_dict=DEFAULT_SETTINGS, test_dict=self.settings)

        # ===== Other checks =====
        if not (0 < self.settings['_epsilon'] < 1):
            raise ValueError("'_epsilon' must be a (small) float in range (0, 1)")
Пример #9
0
def test_adding_paths():
    """
    Test functions for adding paths
    """

    # ----- add_path() -----

    paths = ProjectPaths(ROOT)
    paths.add_path(uid=UID1, path=PATH1, uid_groups=UID_GROUP1)

    # Adding same UID must raise error
    with raises(ValueError):
        paths.add_path(uid=UID1, path=PATH1)

    # Add new path
    paths.add_path(uid=UID2, path=PATH2, uid_groups=(UID_GROUP1, UID_GROUP2))

    assert len(paths._groups[UID_GROUP1]) == 2
    assert len(paths._groups[UID_GROUP2]) == 1
    assert len(paths._abs_paths) == 3

    # Adding invalid group UID must raise error
    with raises(TypeError):
        paths.add_path(uid=str(random.randint(100, 200)),
                       path=PATH1,
                       uid_groups=1234)

    # ----- add_subpath() -----
    paths.add_subpath(uid_parent=UID1,
                      uid=UID3,
                      path=SUBPATH1,
                      uid_groups=UID_GROUP1)
    paths.add_subpath(uid_parent=UID2,
                      uid=UID4,
                      path=SUBPATH2,
                      uid_groups=(UID_GROUP1, UID_GROUP2))

    assert len(paths._groups[UID_GROUP1]) == 4
    assert len(paths._groups[UID_GROUP2]) == 2
    assert len(paths._abs_paths) == 5

    # Adding non-exsiting group UID must raise error
    with raises(ValueError):
        paths.add_subpath(uid_parent='invalid_parent_uid',
                          uid=str(random.randint(100, 200)),
                          path=SUBPATH2,
                          uid_groups=(UID_GROUP1, UID_GROUP2))