"""File and directory operations.
This module includes several functions to handle files and directories, as well
as the functions that process the problem input data file and set the problem
output directory.
Functions
---------
make_directory
Create new directory.
remove_dirs
Remove unrequired directories and files in target directory.
set_input_datafile_path
Process input data file path.
set_problem_dirs
Set output directory structure and output files paths.
"""
#
# Modules
# =============================================================================
# Standard
import os
import shutil
# Local
import ioput.info as info
import ioput.ioutilities as ioutil
#
# Authorship & Credits
# =============================================================================
__author__ = 'Bernardo Ferreira (bernardo_ferreira@brown.edu)'
__credits__ = ['Bernardo Ferreira', ]
__status__ = 'Stable'
# =============================================================================
#
# =============================================================================
#
# Directory operations
# =============================================================================
[docs]def make_directory(dir, option='no_overwrite'):
"""Create new directory.
Parameters
----------
dir : str
Path of new directory.
option : {'no_overwrite', 'overwrite'}, default='no_overwrite'
Either to overwrite or not an existing path.
"""
if option == 'no_overwrite':
os.mkdir(dir)
elif option == 'overwrite':
if not os.path.exists(dir):
os.mkdir(dir)
else:
shutil.rmtree(dir)
os.mkdir(dir)
else:
raise RuntimeError('Unknown option.')
# =============================================================================
[docs]def remove_dirs(target_dir, required_dirnames):
"""Remove unrequired directories and files in target directory.
Parameters
----------
target_dir : str
Path of target directory.
required_dirnames : list[str]
Paths that are to be preserved in target directory.
"""
dirnames = os.listdir(target_dir)
for dir in dirnames:
if dir not in required_dirnames:
path = target_dir + dir
if os.path.isfile(path):
os.remove(path)
else:
shutil.rmtree(path)
#
# Input data file
# =============================================================================
#
# Results directory
# =============================================================================
[docs]def set_problem_dirs(input_file_name, input_file_dir,
is_minimize_output=False, is_null_stdout=False):
"""Set output directory structure.
*Output directory structure:*
.. code-block :: text
example.dat
microstructure_regular_grid.rgmsh
example/
|-----example.screen
|---- microstructure_regular_grid.rgmsh
|---- example.hres
|---- example.efftan
|---- example.refm
|---- example.adapt
|---- offline_stage/
| |---- example.crve
| |---- example_clusters.vti
|
|---- post_process/
|---- example.pvd
|---- VTK/
|---- example.voxout
----
*Glossary: Files and directories*
* **example.dat**
Input data file.
* **regular_grid_mesh.rgmsh**
Spatial discretization file (regular grid of voxels, where each voxel \
is associated with a given material phase ID).
* **example/**
Output directory.
* **example.screen**
File where all the data printed to the default standard output \
device is stored.
* **regular_grid_mesh.rgmsh**
Copy of spatial discretization file.
* **example.hres**
File where the homogenized strain/stress results are stored.
* **example.efftan**
File where the CRVE effective material consistent tangent modulus
is stored.
* **example.refm**
File where data associated with the homogeneous (fictitious)
reference material is stored.
* **example.adapt**
File where the adaptive material phases' number of clusters and \
adaptivity steps are stored (only if clustering adaptivity is \
activated).
* **offline_stage/**
Clustering-based model reduction (offline-stage) directory.
* **example.crve**
File that contains the CRVE instance obtained from the \
clustering-based model reduction (offline-stage), accounting \
for the base clustering and the cluster interaction tensors.
* **example_clusters.vti**
VTK XML file containing spatial (voxelwise) data \
characterizing the CRVE after the clustering-based model \
reduction (offline-stage), namely the material phases and the \
base material clusters.
* **post_processing/**
Post-processing directory.
* **example.pvd**
VTK XML collection file containing the paths to all the VTK \
snapshots taken during the problem solution.
* **VTK/**
VTK XML files directory containing all the snapshots taken \
during the problem solution.
* **example.voxout**
File where material-related quantities defined at the voxel \
level are stored.
----
Parameters
----------
input_file_name : str
Problem input data file name.
input_file_dir : str
Problem input data file directory path.
is_minimize_output : bool, default=False
Output minimization flag.
is_null_stdout : bool, default=False
Suppress execution output to stdout.
Returns
-------
problem_name : str
Problem name.
problem_dir : str
Problem output directory path.
offline_stage_dir : str
Problem output offline-stage subdirectory path.
postprocess_dir : str
Problem output post-processing subdirectory path.
is_same_offstage : bool
`True` if an already existing offline-stage data file is to be
considered, `False` otherwise.
crve_file_path : str
Problem '.crve' output file path.
"""
# Get display features
indent = ioutil.setdisplayfeatures()[2]
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set problem name and output directory
problem_name = input_file_name
problem_dir = input_file_dir + problem_name + '/'
# Set offline-stage and post-processing subdirectories
offline_stage_dir = problem_dir + 'offline_stage' + '/'
postprocess_dir = problem_dir + 'post_processing' + '/'
# Set '.screen' output file path (delete existing file)
ioutil.screen_file_path = problem_dir + input_file_name + '.screen'
if os.path.isfile(ioutil.screen_file_path):
os.remove(ioutil.screen_file_path)
# Set '.crve' output file path
crve_file_path = offline_stage_dir + input_file_name + '.crve'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Disable user prompts
is_user_prompts = True
if is_null_stdout or is_minimize_output:
is_user_prompts = False
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Check if the problem output directory exists
if not os.path.exists(problem_dir):
status = 0
# Create problem output directory and subdirectories
make_directory(problem_dir)
for dir in [offline_stage_dir, postprocess_dir]:
make_directory(dir)
# No previously computed offline-stage data available
is_same_offstage = False
else:
ioutil.print2('\nWarning: The problem output directory for the '
'specified input data file already exists.')
# Ask user if the purpose is to consider previously computed
# offline-stage data ('.crve' output file)
if is_user_prompts:
if os.path.exists(crve_file_path):
is_same_offstage = ioutil.query_yn(
'\nDo you wish to consider the already existent '
'offline-stage \'.crve\' data file?', 'no')
else:
is_same_offstage = False
else:
# Consider existent offline-stage data by default
if os.path.exists(offline_stage_dir) \
and os.path.exists(crve_file_path):
is_same_offstage = True
else:
is_same_offstage = False
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if is_same_offstage:
status = 1
# Raise error if offline-stage subdirectory does not exist
if not os.path.exists(offline_stage_dir):
summary = 'Missing offline-stage subdirectory'
description = 'The subdirectory with the previously computed '\
+ 'offline-stage data files could not be found:' + '\n\n' \
+ indent + '{}'
info.displayinfo('4', summary, description, offline_stage_dir)
# Remove all the existent subdirectories and files except the
# offline-stage subdirectory and the '.screen' output file
required_dirnames = [input_file_name + '.screen', 'offline_stage']
remove_dirs(problem_dir, required_dirnames)
# Create post-processing subdirectory
make_directory(postprocess_dir, 'overwrite')
# Warn user to potential compatibility issues between the problem
# input data file and the existent offline-stage '.crve' data file
if is_user_prompts:
ioutil.useraction(
'\n\nWarning: Please make sure that the problem '
'input data file is consistent with the already'
'\n' + len('Warning: ')*' '
+ 'existent offline-stage \'.crve\' data file '
'(stored in offline_stage/) to avoid ' + '\n'
+ len('Warning: ')*' '
+ 'unexpected errors or misleading conclusions.'
+ '\n\n' + 'Press any key to continue or type '
'\'exit\' to leave: ')
else:
# Ask user if existent problem output directory should be
# overwritten
if is_user_prompts:
is_overwrite = ioutil.query_yn('\nDo you wish to overwrite '
'the existing problem output '
'directory?')
else:
# Overwrite by default
is_overwrite = True
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if is_overwrite:
status = 2
# Remove all existent subdirectories and files except the
# '.screen' output file
required_dirnames = [input_file_name + '.screen']
remove_dirs(problem_dir, required_dirnames)
# Create problem output directory subdirectories
for dir in [offline_stage_dir, postprocess_dir]:
make_directory(dir, 'overwrite')
else:
status = 3
# Display information about the problem directory and status
info.displayinfo('-1', problem_dir, status)
# Return
return problem_name, problem_dir, offline_stage_dir, postprocess_dir, \
is_same_offstage, crve_file_path