Skip to content

Commit

Permalink
Change np.float to np.float64, fix matprlotlib show warning, fix addi…
Browse files Browse the repository at this point in the history
…tional warnings when engine fails to generate code
  • Loading branch information
noscode committed Jun 6, 2023
1 parent c8d96a5 commit 9508a8b
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 49 deletions.
69 changes: 67 additions & 2 deletions gadma/cli/settings_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
VCFDataHolder, check_and_return_projections_and_labels
from ..engines import get_engine, MomentsEngine, MomentsLdEngine
from ..engines import DadiEngine
from ..engines import all_engines, all_drawing_engines
from ..models import StructureDemographicModel, CustomDemographicModel
from ..engines import all_engines, all_drawing_engines, all_available_engines
from ..models import StructureDemographicModel, CustomDemographicModel,\
EpochDemographicModel
from ..optimizers import get_local_optimizer, get_global_optimizer
from ..optimizers import LinearConstrain
from ..utils import check_dir_existence, check_file_existence, abspath,\
Expand Down Expand Up @@ -1380,6 +1381,70 @@ def Nanc_will_be_available(self):
return True
return False

def get_available_engines(self, print_warnings=False):
"""
Returns ids of engines that are available for current settings.
For examples if no sequence length or mutation rate is given
then momi2 engine will be unavailable for code generation.
"""
available_engines = []
model = self.get_model()
if (isinstance(model, EpochDemographicModel) or
isinstance(model, TreeDemographicModel)):
Nanc_will_be = self.Nanc_will_be_available()
L = self.data_holder.get_total_sequence_length()
L_is_None = L is None
mu_is_None = self.mutation_rate is None
if L_is_None and mu_is_None:
msg = "`Sequence length` and `Mutation rate` are required"
elif L_is_None:
msg = "`Sequence length` is reqiered"
elif mu_is_None:
msg = "`Mutation rate` is required"
for engine in all_available_engines():
if engine.id == "demes" and not Nanc_will_be:
if print_warnings:
warnings.warn(
f"Code for demes will not be generated as {msg}"
)
continue
if (engine.id == "momi2" and
(not Nanc_will_be or L_is_None)):
if print_warnings:
warnings.warn(
f"Code for momi2 will not be generated as {msg}"
)
continue
# conditions for momentsLD
if (engine.id == "momentsLD" and
self.engine != "momentsLD"):
# The following lines are already checked before
# have_vcf = isinstance(self.engine.data_holder,
# VCFDataHolder)
# if not have_vcf:
# warnings.warn(
# "Code for momentsLD will not be generated"
# " as VCF file is required as `Input data`"
# )
# continue
# bed_dir = engine.data_holder.bed_files_dir
# have_bed = bed_dir is not None
preproc = self.preprocessed_data is not None
if not preproc:
if print_warnings:
warnings.warn(
"Code for momentsLD will not be generated"
" as data was not preprocessed for it (run"
" gadma-precompute_ld_data script on the VCF"
" file first)"
)
continue
available_engines.append(engine.id)
else:
assert isinstance(self.model, CustomDemographicModel)
available_engines.append(self.engine.id)
return available_engines

def is_valid(self):
"""
Checks that settings are fine. Rises errors if something is not right.
Expand Down
3 changes: 3 additions & 0 deletions gadma/core/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ def main():
sys.stdout = StdAndFileLogger(log_file, settings_storage.silence)
sys.stderr = StdAndFileLogger(log_file, stderr=True)

# Check what engines will be available and print warnings
settings_storage.get_available_engines(print_warnings=True)

try:
# Data reading
print("Data reading")
Expand Down
62 changes: 26 additions & 36 deletions gadma/core/core_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ def __init__(self, index, shared_dict, settings):
self.optimize_kwargs['global_maxeval'] = settings.global_maxeval
self.optimize_kwargs['local_maxiter'] = settings.local_maxiter
self.optimize_kwargs['local_maxeval'] = settings.local_maxeval
# Check input settings and get what engines will be available
self.available_engines = self.settings.get_available_engines()
# Create directory for pictures if needed
if self.settings.draw_models_every_n_iteration != 0:
self.pictures_dir = os.path.join(self.output_dir, 'pictures')
Expand All @@ -103,36 +105,9 @@ def __init__(self, index, shared_dict, settings):
if self.settings.print_models_code_every_n_iteration != 0:
self.code_dir = os.path.join(self.output_dir, 'code')
ensure_dir_existence(self.code_dir)
# If our model is built via gadma then we can write code for
# all engines.
if isinstance(self.model, EpochDemographicModel):
Nanc_will_be = self.settings.Nanc_will_be_available()
L = self.settings.data_holder.get_total_sequence_length()
L_is_None = L is None
is_custom = isinstance(self.engine.model,
CustomDemographicModel)
for engine in all_available_engines():
if engine.id == "demes" and not Nanc_will_be:
continue
if (engine.id == "momi2" and
(not Nanc_will_be or L_is_None) and
not is_custom):
continue
if is_custom and self.engine.id != engine.id:
continue
# conditions for momentsLD
if engine.id == "momentsLD":
have_vcf = isinstance(engine.data_holder,
VCFDataHolder)
if not have_vcf:
continue
bed_dir = engine.data_holder.bed_files_dir
have_bed = bed_dir is not None
preproc = engine.preprocessed_data is not None
if not have_bed and not preproc:
continue
engine_dir = os.path.join(self.code_dir, engine.id)
ensure_dir_existence(engine_dir)
for engine_id in self.available_engines:
engine_dir = os.path.join(self.code_dir, engine.id)
ensure_dir_existence(engine_dir)
# Set counters to zero for callbacks to count number of their calls
self.draw_iter_callback_counter = 0
self.code_iter_callback_counter = 0
Expand Down Expand Up @@ -211,8 +186,13 @@ def base_callback(self, x, y):
save_code_file = os.path.join(self.output_dir,
prefix + "_model")
try:
generate_code_to_file(x, self.engine,
self.settings, save_code_file)
generate_code_to_file(
x,
self.engine,
self.settings,
save_code_file,
self.available_engines,
)
except Exception:
pass

Expand Down Expand Up @@ -370,8 +350,13 @@ def intermediate_callback(self, x, y):
print(f"{bcolors.WARNING}Run {self.index}: failed to draw model "
f"due to the following exception: {e}{bcolors.ENDC}")
try:
generate_code_to_file(x, self.engine,
self.settings, save_code_file)
generate_code_to_file(
x,
self.engine,
self.settings,
save_code_file,
self.available_engines,
)
except Exception as e:
print(f"{bcolors.WARNING}Run {self.index}: failed to generate code"
f" due to the following exception: {e}{bcolors.ENDC}")
Expand All @@ -398,8 +383,13 @@ def draw_model_in_output_dir(self, x, y,
save_plot_file = os.path.join(self.output_dir, prefix + "_model.png")
save_code_file = os.path.join(self.output_dir, prefix + "_model")
try:
generate_code_to_file(x, self.engine,
self.settings, save_code_file)
generate_code_to_file(
x,
self.engine,
self.settings,
save_code_file,
self.available_engines,
)
except Exception:
pass
try:
Expand Down
19 changes: 16 additions & 3 deletions gadma/core/draw_and_generate_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ def draw_plots_to_file(x, engine, settings, filename, fig_title):
new_img.save(filename)


def generate_code_to_file(x, engine, settings, filename):
def generate_code_to_file(
x, engine, settings, filename, available_engines=None,
):
"""
Generates code of demographic model to file. Settings are required to get
``engine`` arguments in :func:`evaluation` function.
Expand All @@ -156,7 +158,12 @@ def generate_code_to_file(x, engine, settings, filename):
:type settings: :class:`gadma.cli.settings_storage.SettingsStorage`
:param filename: File name to save picture.
:type filename: str
:param available_engines: list of engines to generate code for.
If None then for all available engines.
"""
if available_engines is None:
available_engines = [eng.id for eng in all_available_engines()]

pos = filename.rfind('.')
if pos == -1 or filename[pos:] != '.py':
pos = len(filename)
Expand All @@ -169,7 +176,7 @@ def generate_code_to_file(x, engine, settings, filename):
)
# Generate code
if isinstance(engine.model, EpochDemographicModel):
engines_ids = [eng.id for eng in all_available_engines()]
engines_ids = available_engines
if not settings.Nanc_will_be_available():
if "demes" in engines_ids:
engines_ids.remove("demes")
Expand Down Expand Up @@ -342,7 +349,13 @@ def print_runs_summary(start_time, shared_dict, settings):
print(f"{bcolors.WARNING}Run {index} warning: failed to draw model"
f" due to the following exception: {e}{bcolors.ENDC}.")
try:
generate_code_to_file(x, engine, settings, save_code_file)
generate_code_to_file(
x,
engine,
settings,
save_code_file,
settings.get_available_engines(),
)
except Exception as e:
gener = False
print(
Expand Down
6 changes: 5 additions & 1 deletion gadma/engines/dadi_moments_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,11 @@ def draw_data_comp_plot(self, values, grid_sizes, save_file=None,
)
# Draw
if n_pop == 1:
self.base_module.Plotting.plot_1d_comp_Poisson(model, self.data)
self.base_module.Plotting.plot_1d_comp_Poisson(
model,
self.data,
show=show
)
if show:
plt.show()
else:
Expand Down
8 changes: 4 additions & 4 deletions gadma/optimizers/linear_constrain.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class LinearConstrain(object):
:param ub: Upper bound.
"""
def __init__(self, A, lb, ub):
lb = np.nan_to_num(np.array(lb, dtype=np.float), nan=-np.inf)
ub = np.nan_to_num(np.array(ub, dtype=np.float), nan=np.inf)
lb = np.nan_to_num(np.array(lb, dtype=np.float64), nan=-np.inf)
ub = np.nan_to_num(np.array(ub, dtype=np.float64), nan=np.inf)
self.constrain = scipy.optimize.LinearConstraint(np.array(A), lb, ub)

def _get_value(self, x):
Expand Down Expand Up @@ -87,13 +87,13 @@ def A(self):

@lb.setter
def lb(self, new_value):
new_value = np.nan_to_num(np.array(new_value, dtype=np.float),
new_value = np.nan_to_num(np.array(new_value, dtype=np.float64),
nan=-np.inf)
self.constrain.lb = new_value

@ub.setter
def ub(self, new_value):
new_value = np.nan_to_num(np.array(new_value, dtype=np.float),
new_value = np.nan_to_num(np.array(new_value, dtype=np.float64),
nan=np.inf)
self.constrain.ub = new_value

Expand Down
2 changes: 1 addition & 1 deletion gadma/optimizers/local_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def _optimize(self, f, variables, x0, options,
"""
Run Scipy optimization.
"""
x0 = np.array(x0, dtype=np.float)
x0 = np.array(x0, dtype=np.float64)
y = f(x0)
iter_callback(x0, y, [x0], [y])

Expand Down
4 changes: 2 additions & 2 deletions gadma/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def logarithm_transform(x):
"""
Transforms ``x`` by applying ``numpy.log`` on it.
"""
if isinstance(x, (int, float, np.integer, np.float)):
if isinstance(x, (int, float, np.integer, np.float64)):
x = [x]
if not isinstance(x, (list, np.ndarray)):
return x
Expand Down Expand Up @@ -68,7 +68,7 @@ def exponent_transform(x):
"""
Transforms ``x`` by applying ``numpy.exp`` on it.
"""
if isinstance(x, (int, float, np.integer, np.float)):
if isinstance(x, (int, float, np.integer, np.float64)):
x = [x]
if not isinstance(x, (list, np.ndarray)):
return x
Expand Down

0 comments on commit 9508a8b

Please sign in to comment.