Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Documentation/Settings_in_Optimization_Dict.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Assuming you define the settings in the form of a .json file, the general struct
"create_logfile": true, # determines if you want to save the log-file
"console_info": true, # determines if you want the optimization output printed to the console
"dump_format": "npz", # format of the results file
"continuation_datetime": "YYYYmmdd_HHMMSS" # date of optimization to be continued
"algorithm_settings": {...}, # settings related to the algorithm
"pulses": [{...}, {...}, ...], # list of pulses and their settings
"parameters": [{...}, {...}, ...], # list of parameters and their settings
Expand All @@ -30,6 +31,8 @@ The `console_info` key determines if the optimization output is shown in the ter

The `dump_format` key specifies the format of the results file (best controls and some meta data). Currently you can choose between "npz" and "json". The default (if you do not give this key) is "npz".

The `continuation_datetime` key determines wether an existing optimization job should be continued and the results saved in the corresponding folder. If intended, the corresponding date and time should be provided in the format "YYYYmmdd_HHMMSS" and the corresponding job name speficied in `optimization_client_name`. QuOCS will then try to import the best controls found in the previous run as initial values for the continuation. Here make sure, to use the same names for pulses and parameters in the `optimiaztion_dictionary` as in the previous run. The default of this key is "no" and will create a new folder with a timestamp of the point of creation.

**Tip:** You can also change specific entries in the code after reading in the .json file if you, e.g., want to sweep certain parameters or have the name of the optimization defined on runtime.


Expand Down
1 change: 1 addition & 0 deletions Examples/execute_dCRAB.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,6 @@ def main(optimization_dictionary: dict):
print("\nBest FoM: {}".format(optimization_obj.opt_alg_obj.best_FoM))



if __name__ == "__main__":
main(readjson(os.path.join(os.getcwd(), "settings_dCRAB.json")))
9 changes: 8 additions & 1 deletion src/quocslib/Optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from quocslib.communication.AllInOneCommunication import AllInOneCommunication
from quocslib.utils.BestDump import BestDump
from quocslib.utils.AbstractFoM import AbstractFoM
from quocslib.utils.Import_previous_results import update_opti_dict


class Optimizer:
Expand Down Expand Up @@ -58,6 +59,8 @@ def __init__(self,
self.dump_format = optimization_dict.setdefault("dump_format", "npz")
self.optimization_direction = optimization_dict["algorithm_settings"].setdefault("optimization_direction",
"minimization")
self.continuation_datetime = optimization_dict.setdefault("continuation_datetime", "no")

self.communication_obj = AllInOneCommunication(interface_job_name=self.interface_job_name,
FoM_obj=FoM_object,
handle_exit_obj=handle_exit_obj,
Expand All @@ -66,7 +69,11 @@ def __init__(self,
create_logfile=self.create_logfile,
console_info=self.console_info,
dump_format=self.dump_format,
optimization_direction=self.optimization_direction)
optimization_direction=self.optimization_direction,
continuation_datetime=self.continuation_datetime)

if self.communication_obj.is_continuation:
optimization_dict = update_opti_dict(optimization_dict, self.communication_obj)

self.results_path = self.communication_obj.results_path

Expand Down
29 changes: 24 additions & 5 deletions src/quocslib/communication/AllInOneCommunication.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def __init__(self,
create_logfile: bool = True,
console_info: bool = True,
dump_format: str = "npz",
optimization_direction: str = "minimization"):
optimization_direction: str = "minimization",
continuation_datetime: str = "no"):
"""
In case the user chooses to run the optimization in his device, this class is used by the OptimizationAlgorithm.
The objects to dump the results, calculate the figure of merit, and the logger are created here.
Expand All @@ -58,25 +59,43 @@ def __init__(self,
(self.message_signal, self.FoM_plot_signal, self.controls_update_signal) = comm_signals_list
# Pre job name
pre_job_name = interface_job_name
# Optimization folder name
optimization_folder = "QuOCS_Results"
# Datetime for 1-1 association
self.date_time = str(time.strftime("%Y%m%d_%H%M%S"))
# Check, if optimization is continuation
self.is_continuation = False
queued_logger_info = None
if continuation_datetime == "no":
self.date_time = str(time.strftime("%Y%m%d_%H%M%S"))
else:
continuation_job_folder = os.path.join(os.getcwd(), optimization_folder, continuation_datetime + "_" + pre_job_name)
if not os.path.isdir(continuation_job_folder):
queued_logger_info = "Continuation attempt: No Folder " + continuation_job_folder + " found, new folder created"
self.date_time = str(time.strftime("%Y%m%d_%H%M%S"))
else:
self.date_time = continuation_datetime
self.is_continuation = True
queued_logger_info = "Continue optimization from " + continuation_datetime + "_" + pre_job_name
# Client job name to send to the Server
self.client_job_name = self.date_time + "_" + pre_job_name
###
# Logging, Results, Figure of merit evaluation ...
###
# Optimization folder
optimization_folder = "QuOCS_Results"
# Optimization folder
self.results_path = os.path.join(os.getcwd(), optimization_folder, self.client_job_name)
if not os.path.isdir(os.path.join(os.getcwd(), optimization_folder)):
os.makedirs(os.path.join(os.getcwd(), optimization_folder))
# Create the folder for logging and results
os.makedirs(self.results_path)
if not os.path.isdir(self.results_path):
os.makedirs(self.results_path)
# Write the current quocs lib version in the file
with open(os.path.join(self.results_path, "quocs_version.txt"), "w") as version_file:
version_file.write("QuOCS library version: {0}".format(quocslib_version))
# Create logging object
self.logger = create_logger(self.results_path, self.date_time, create_logfile=create_logfile, console_info=console_info)
# print queued logger info
if not queued_logger_info == None:
self.logger.info(queued_logger_info)
# Print function evaluation and figure of merit
self.print_general_log = True
# Figure of merit object
Expand Down
3 changes: 2 additions & 1 deletion src/quocslib/tools/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ def create_logger(results_path, date_time, create_logfile=True, console_info=Tru
console_handler.setFormatter(logging.Formatter(print_format))
# Log file handler
if create_logfile:
file_handler = logging.FileHandler(log_filename)
# file_handler = logging.FileHandler(log_filename)
file_handler = logging.FileHandler(log_filename, mode='a')
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(logging.Formatter(log_format, date_format))
# Add handler for logfile to the logger
Expand Down
57 changes: 57 additions & 0 deletions src/quocslib/utils/Import_previous_results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Copyright 2021- QuOCS Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import os
import numpy as np
from quocslib.utils.inputoutput import readjson


def update_opti_dict(optimization_dict: dict, comm_obj: object) -> dict:
"""
Load optimal results of previous run and initial guess into an optimization dictionary
:param dict optimization_dictionary: optimization_dictionary to be updated
:comm_obj: communication object of optimization
:return dict: updated optimization dictionary
"""

try:
if optimization_dict["dump_format"] == "json":
best_res_path = os.path.join(comm_obj.results_path, comm_obj.date_time + "_best_controls.json")
best_res = readjson(best_res_path)
else:
best_res_path = os.path.join(comm_obj.results_path, comm_obj.date_time + "_best_controls.npz")
best_res = np.load(best_res_path)

for pulse in optimization_dict["pulses"]: # use same optimization dictionary as in previous optimization
pulse_name = pulse["pulse_name"] # make sure to use the same pulse names in opti_dict as in best_controls
prev_opt_pulse = best_res[pulse_name]
initial_guess = {"function_type": "list_function", "list_function": prev_opt_pulse}
pulse["initial_guess"] = initial_guess
comm_obj.logger.info(f"Initial guess for pulse {pulse_name} imported from previous results")

for param in optimization_dict["parameters"]:
param_name = param["parameter_name"]
prev_opt_param = best_res[param_name]
param["initial_value"] = prev_opt_param
comm_obj.logger.info(f"Initial guess for parameter {param_name} imported from previous results")

except:
comm_obj.logger.warn("Previous optimal controls could not be imported for continuation."
" Check if ..._best_controls...-file exists and pulse/paremeter names coincide with optimization dictionary")

return optimization_dict


Loading