Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1810 fix #1825

Merged
merged 80 commits into from Feb 21, 2023
Merged

1810 fix #1825

merged 80 commits into from Feb 21, 2023

Conversation

emilydriano
Copy link
Contributor

@emilydriano emilydriano commented Aug 25, 2022

Addresses core issues of #1810
This PR incorporates id-generation plugins for item ID's. The name of the plugin the user desires to use can be specified in the .ini file under [COMMON] > 'id_generator'. The 2 plugins we defined are:

  • uuid: returns a uuid as the item id (default option)
  • item_sequence: returns a sequential id for the respective item based on the most recently created/used id for that respective item type. A sequence file is created that keeps track of these sequential ids for each item type (experiment, simulation, etc) and returns and stores the next id. The user can customize both the sequence file name as well as the id string format using the 'sequence_file' and 'id_format_str' options under an [item_sequence] section in the .ini file. See added docs for more detail and an example.

Documentation and tests were also added for this feature.

*Note - the id sequential generator plugin is intended to be used with Slurm, not with COMPS.

To support this, we also added tickets related
#1930
#1936
#1937
#1938
#1939
#1954

@shchen-idmod
Copy link
Collaborator

shchen-idmod commented Aug 29, 2022

My test take forever with script below and eventual throw error:

    def test_perf(self):
       
        parser = IdmConfigParser()
        parser._load_config_file(file_name='idmtools_slurm.ini')
        task = JSONConfiguredPythonTask(script_path=os.path.join(COMMON_INPUT_PATH, "python", "model3.py"),
                                        envelope="parameters", parameters=(dict(c=0)))
        platform = Platform('SLURM_TEST')
        ts = TemplatedSimulations(base_task=task)
        e = Experiment.from_template(ts)
        from idmtools.builders import SimulationBuilder
        builder = SimulationBuilder()

        def param_update(simulation, param, value):
            return simulation.task.set_parameter(param, value)
        builder.add_sweep_definition(partial(param_update, param="a"), range(300))
        builder.add_sweep_definition(partial(param_update, param="b"), range(500))
        e.simulations.add_builder(builder)
        suite = add_dammy_suite(e)
        suite.run(platform=platform, dry_run=True)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\idmtools\core\interfaces\irunnable_entity.py:104: in run
    p.run_items(self, wait_on_done_progress=wait_on_done_progress, **run_opts)
..\idmtools\entities\iplatform.py:507: in run_items
    getattr(self, interface).run_item(item, **kwargs)
..\idmtools\entities\iplatform_ops\iplatform_suite_operations.py:193: in run_item
    self.pre_run_item(suite, **kwargs)
..\idmtools\entities\iplatform_ops\iplatform_suite_operations.py:165: in pre_run_item
    self.platform.run_items(exps_to_commission, **kwargs)
..\idmtools\entities\iplatform.py:507: in run_items
    getattr(self, interface).run_item(item, **kwargs)
..\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:260: in run_item
    self.pre_run_item(experiment, **kwargs)
..\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:225: in pre_run_item
    experiment.simulations = self.platform._create_items_of_type(experiment.simulations, ItemType.SIMULATION, **kwargs)
..\idmtools\entities\iplatform.py:469: in _create_items_of_type
    ni = getattr(self, interface).batch_create(items, **kwargs)
..\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:134: in batch_create
    return batch_create_items(sims, create_func=self.create, display_progress=display_progress,
..\idmtools\entities\iplatform_ops\utils.py:151: in batch_create_items
    results = show_progress_of_batch(prog, futures)
..\idmtools\entities\iplatform_ops\utils.py:172: in show_progress_of_batch
    result = future.result()
c:\python39\lib\concurrent\futures\_base.py:438: in result
    return self.__get_result()
c:\python39\lib\concurrent\futures\_base.py:390: in __get_result
    raise self._exception
c:\python39\lib\concurrent\futures\thread.py:52: in run
    result = self.fn(*self.args, **self.kwargs)
..\idmtools\entities\iplatform_ops\utils.py:61: in item_batch_worker_thread
    ret.append(create_func(item, **kwargs))
..\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:99: in create
    simulation._platform_object = self.platform_create(simulation, **kwargs)
..\..\idmtools_platform_slurm\idmtools_platform_slurm\platform_operations\simulation_operations.py:56: in platform_create
    if not isinstance(simulation.uid, UUID):
..\idmtools\core\interfaces\iitem.py:51: in uid
    self._uid = plugin.idmtools_generate_id(self)
..\idmtools\plugins\item_sequence.py:58: in idmtools_generate_id
    data = load_existing_sequence_data(sequence_file)
..\idmtools\plugins\item_sequence.py:40: in load_existing_sequence_data
    data = json.load(file)
c:\python39\lib\json\__init__.py:293: in load
    return loads(fp.read(),
c:\python39\lib\json\__init__.py:346: in loads
    return _default_decoder.decode(s)
c:\python39\lib\json\decoder.py:337: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <json.decoder.JSONDecoder object at 0x0000018F58CE05B0>, s = '', idx = 0

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

c:\python39\lib\json\decoder.py:355: JSONDecodeError

idmtools_slurm.ini:

[COMMON]
id_generator = item_sequence

[SLURM_TEST]
type = Slurm
job_directory = DEST
mode = LOCAL

[item_sequence]
sequence_file = item_sequences.json
id_format_str = {item_name}{data[item_name]:06d}

@shchen-idmod
Copy link
Collaborator

shchen-idmod commented Aug 30, 2022

test_id.py.txt
For above test (remove .txt)

  1. I print simulation.id before and after call run. then print different format:
    Before run
    Simulation000000
    Simulation000001
    Simulation000002
    Simulation000003
    Simulation000004
    Simulation000005
    Simulation000006
    Simulation000007
    Simulation000008
    None
    After run
    b5d6f315-53a4-4a07-a28f-25036f3c3897
    a9ab64a4-ba19-42aa-a885-cc7bbd506c2a
    72874eb6-bb8e-4f3a-93fd-aef0d71a630d
    7a7e498e-8028-47e5-9d19-f8a280a268ed
    988560d6-a132-4693-b211-8690e5119c2e
    a34940f7-787a-434b-9514-547f842450db
    ee2c6967-46c8-48e9-ab0d-3b2828941004
    619d3914-f191-4be0-8b54-6ceadb942ae0
    e3c0561a-9e41-4fd5-9563-1a100e5f6686

  2. Also item_sequences.json says simulation is 26. I only generate 9 sims.
    {"Unknown": 0, "Simulation": 26, "Experiment": 0, "Suite": 0}

  3. There is "Unknown" which I do not know where it come from

I kind of know where 26 come from:
a) If I comment out last 4 lines of code(starting from suite.run), then sequences seems correct as Simulation: 8(0 base, so total is 9).
b) If I only comment out first print statement for id, [print(sim.id) for sim in simulations], then sequence count says 17(which is 8 + 9=17). It obvious should not add another 9.
c) If I do not comment out anything, it is 26=8+9+9 which added another 9 by calling sim.id 9 times in print statement

@shchen-idmod
Copy link
Collaborator

shchen-idmod commented Sep 7, 2022

test_1.py.txt

idmtools_1.ini
[COMMON]
id_generator = item_sequence

[MTest]
type = Slurm

[item_sequence]
sequence_file = item_sequences.json
id_format_str = {item_name}{data[item_name]:06d}
  1. Get following Assets error in first run
test_1.py::TestItemSequence::test_1 FAILED                               [100%]2022-09-06 23:56:11,551 BMGF-R913QDCE idmtools.config.idm_config_parser[2116] DEBUG Looking for config file in C:\Users\sharonch\github\idmtools\idmtools_platform_slurm\tests
You are using a development version of idmtools, version 1.6.7+nightly!
INI File Used: C:\Users\sharonch\github\idmtools\idmtools_platform_slurm\tests\idmtools_1.ini

[MTest]
{
   "type": "Slurm"
}
...
test_1.py:68: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\idmtools_core\idmtools\entities\experiment.py:544: in run
    p.run_items(self, **run_opts)
..\..\idmtools_core\idmtools\entities\iplatform.py:507: in run_items
    getattr(self, interface).run_item(item, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:260: in run_item
    self.pre_run_item(experiment, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:225: in pre_run_item
    experiment.simulations = self.platform._create_items_of_type(experiment.simulations, ItemType.SIMULATION, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform.py:469: in _create_items_of_type
    ni = getattr(self, interface).batch_create(items, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:134: in batch_create
    return batch_create_items(sims, create_func=self.create, display_progress=display_progress,
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:151: in batch_create_items
    results = show_progress_of_batch(prog, futures)
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:172: in show_progress_of_batch
    result = future.result()
c:\python39\lib\concurrent\futures\_base.py:438: in result
    return self.__get_result()
c:\python39\lib\concurrent\futures\_base.py:390: in __get_result
    raise self._exception
c:\python39\lib\concurrent\futures\thread.py:52: in run
    result = self.fn(*self.args, **self.kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:61: in item_batch_worker_thread
    ret.append(create_func(item, **kwargs))
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:99: in create
    simulation._platform_object = self.platform_create(simulation, **kwargs)
..\idmtools_platform_slurm\platform_operations\simulation_operations.py:61: in platform_create
    self.platform._assets.link_common_assets(simulation)
..\idmtools_platform_slurm\platform_operations\asset_collection_operations.py:68: in link_common_assets
    self.platform._op_client.link_dir(common_asset_dir, link_dir)
..\idmtools_platform_slurm\slurm_operations.py:243: in link_dir
    link.symlink_to(target)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = WindowsPath('C:/Users/sharonch/github/idmtools/idmtools_platform_slurm/tests/DEST/Suite000000/Experiment000000/Simulation000500/Assets')
target = WindowsPath('C:/Users/sharonch/github/idmtools/idmtools_platform_slurm/tests/DEST/Suite000000/Experiment000000/Assets')
target_is_directory = False

    def symlink_to(self, target, target_is_directory=False):
        """
        Make this path a symlink pointing to the target path.
        Note the order of arguments (link, target) is the reverse of os.symlink.
        """
>       self._accessor.symlink(target, self, target_is_directory)
E       FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'C:\\Users\\sharonch\\github\\idmtools\\idmtools_platform_slurm\\tests\\DEST\\Suite000000\\Experiment000000\\Assets' -> 'C:\\Users\\sharonch\\github\\idmtools\\idmtools_platform_slurm\\tests\\DEST\\Suite000000\\Experiment000000\\Simulation000500\\Assets'

c:\python39\lib\pathlib.py:1393: FileExistsError

  1. get run_sumulation.sh error if run again without clear job_directory
self = WindowsPath('C:/Users/sharonch/github/idmtools/idmtools_platform_slurm/tests/DEST/Suite000000/Experiment000000/run_simulation.sh')
target = WindowsPath('C:/Users/sharonch/github/idmtools/idmtools_platform_slurm/idmtools_platform_slurm/assets/run_simulation.sh')
target_is_directory = False

    def symlink_to(self, target, target_is_directory=False):
        """
        Make this path a symlink pointing to the target path.
        Note the order of arguments (link, target) is the reverse of os.symlink.
        """
>       self._accessor.symlink(target, self, target_is_directory)
E       FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'C:\\Users\\sharonch\\github\\idmtools\\idmtools_platform_slurm\\idmtools_platform_slurm\\assets\\run_simulation.sh' -> 'C:\\Users\\sharonch\\github\\idmtools\\idmtools_platform_slurm\\tests\\DEST\\Suite000000\\Experiment000000\\run_simulation.sh'

c:\python39\lib\pathlib.py:1393: FileExistsError

@shchen-idmod
Copy link
Collaborator

idmtools_1.ini

[COMMON]
id_generator = item_sequence

[MTest]
type = Slurm

[item_sequence]
sequence_file = item_sequences.json
id_format_str = {item_name}{data[item_name]:06d}

Run following code by delete DEST folder first, always get this error:

Commissioning Simulations:   0%|          | 0/500 [00:00<?, ?simulation/s]            
test_1.py:45 (TestItemSequence.test_1)
self = <tests.test_1.TestItemSequence testMethod=test_1>

    @pytest.mark.serial
    @pytest.mark.performance
    def test_1(self):
        clear_id_cache()
        parser = IdmConfigParser()
        parser._load_config_file(file_name='idmtools_1.ini')
        sequence_file = self.get_sequence_file()
        platform = Platform('MTest', missing_ok=True, job_directory="DEST")
        task = JSONConfiguredPythonTask(script_path=os.path.join(COMMON_INPUT_PATH, "python", "model1.py"),
                                        envelope="parameters", parameters=(dict(c=0)))
        ts = TemplatedSimulations(base_task=task)
        e = Experiment.from_template(ts)
        from idmtools.builders import SimulationBuilder
        builder = SimulationBuilder()
    
        def param_update(simulation, param, value):
            return simulation.task.set_parameter(param, value)
    
        builder.add_sweep_definition(partial(param_update, param="a"), range(10 * get_performance_scale()))
        builder.add_sweep_definition(partial(param_update, param="b"), range(50))
        e.simulations.add_builder(builder)
        add_dummy_suite(e)
>       e.run(platform=platform, wait_until_done=False, dry_run=True)

test_1.py:68: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\..\idmtools_core\idmtools\entities\experiment.py:544: in run
    p.run_items(self, **run_opts)
..\..\idmtools_core\idmtools\entities\iplatform.py:507: in run_items
    getattr(self, interface).run_item(item, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:260: in run_item
    self.pre_run_item(experiment, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_experiment_operations.py:225: in pre_run_item
    experiment.simulations = self.platform._create_items_of_type(experiment.simulations, ItemType.SIMULATION, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform.py:469: in _create_items_of_type
    ni = getattr(self, interface).batch_create(items, **kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:134: in batch_create
    return batch_create_items(sims, create_func=self.create, display_progress=display_progress,
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:151: in batch_create_items
    results = show_progress_of_batch(prog, futures)
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:172: in show_progress_of_batch
    result = future.result()
c:\python39\lib\concurrent\futures\_base.py:438: in result
    return self.__get_result()
c:\python39\lib\concurrent\futures\_base.py:390: in __get_result
    raise self._exception
c:\python39\lib\concurrent\futures\thread.py:52: in run
    result = self.fn(*self.args, **self.kwargs)
..\..\idmtools_core\idmtools\entities\iplatform_ops\utils.py:61: in item_batch_worker_thread
    ret.append(create_func(item, **kwargs))
..\..\idmtools_core\idmtools\entities\iplatform_ops\iplatform_simulation_operations.py:99: in create
    simulation._platform_object = self.platform_create(simulation, **kwargs)
..\idmtools_platform_slurm\platform_operations\simulation_operations.py:59: in platform_create
    self.platform._op_client.mk_directory(simulation)
..\idmtools_platform_slurm\slurm_operations.py:214: in mk_directory
    target = self.get_directory(item)
..\idmtools_platform_slurm\slurm_operations.py:171: in get_directory
    item_dir = Path(exp_dir, item.id)
..\..\idmtools_core\idmtools\core\interfaces\iitem.py:97: in id
    if self.uid:
..\..\idmtools_core\idmtools\core\interfaces\iitem.py:65: in uid
    self._uid = plugin.idmtools_generate_id(self)
..\..\idmtools_core\idmtools\plugins\item_sequence.py:72: in idmtools_generate_id
    data = load_existing_sequence_data(sequence_file)
..\..\idmtools_core\idmtools\plugins\item_sequence.py:41: in load_existing_sequence_data
    data = json.load(file)
c:\python39\lib\json\__init__.py:293: in load
    return loads(fp.read(),
c:\python39\lib\json\__init__.py:346: in loads
    return _default_decoder.decode(s)
c:\python39\lib\json\decoder.py:337: in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <json.decoder.JSONDecoder object at 0x000001EE071105B0>, s = '', idx = 0

    def raw_decode(self, s, idx=0):
        """Decode a JSON document from ``s`` (a ``str`` beginning with
        a JSON document) and return a 2-tuple of the Python
        representation and the index in ``s`` where the document ended.
    
        This can be used to decode a JSON document from a string that may
        have extraneous data at the end.
    
        """
        try:
            obj, end = self.scan_once(s, idx)
        except StopIteration as err:
>           raise JSONDecodeError("Expecting value", s, err.value) from None
E           json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

c:\python39\lib\json\decoder.py:355: JSONDecodeError

@@ -231,3 +234,9 @@ def post_run_item(self, experiment: Experiment, **kwargs):
sim_path = Path(exp_path, "simulation_index.json")
with open(sim_path, "w") as f:
json.dump([s.id for s in experiment.simulations], f)

if IdmConfigParser.get_option(None, "id_generator", "uuid").lower() == "item_sequence":
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the almost exactly what super class function of post_run_item does (still missing experiment.post_run(self.platform). so no need to copy code. just need call super function.

@shchen-idmod
Copy link
Collaborator

def get(self, experiment_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,

def get(self, simulation_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,

def get(self, suite_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,

def get(self, workflow_item_id: UUID, columns: Optional[List[str]] = None, load_children: Optional[List[str]] = None,

def get(self, asset_collection_id: Optional[UUID], load_children: Optional[List[str]] = None, query_criteria: Optional[QueryCriteria] = None, **kwargs) -> COMPSAssetCollection:

You still have lot of places using UUID for id as above lines. Do you intend to do that?

@shchen-idmod shchen-idmod self-requested a review January 10, 2023 19:12
Copy link
Collaborator

@shchen-idmod shchen-idmod left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested the latest fixes. Even there are still few issues(like can not random print id, too fridge if let user define sequence file), but overall feature is good.

Maybe we should consider to release to a separate branch instead of dev branch until we are sure to release this feature. Meanwhile we can keep develop on dev branch and release new stuff

@shchen-idmod
Copy link
Collaborator

shchen-idmod commented Feb 6, 2023

Can we fix conflicts? @emilykclaps

@emilydriano
Copy link
Contributor Author

@shchen-idmod just resolved conflicts. Where are we with this PR? Can we merge to dev, or did you want to release to separate branch until ready to merge? Thx!

@shchen-idmod
Copy link
Collaborator

FAILED test_slurm_cancel1.py::TestSlurmCanceling::test_canceling_a_full_experiment - NameError: name 'meta' is not defined
FAILED test_slurm_cancel1.py::TestSlurmCanceling::test_canceling_a_full_suite - NameError: name 'meta' is not defined
FAILED test_slurm_cancel1.py::TestSlurmCanceling::test_canceling_a_single_simulation - NameError: name 'meta' is not defined
You may missing something from latest code.

# Conflicts:
#	idmtools_platform_slurm/idmtools_platform_slurm/platform_operations/experiment_operations.py
@shchen-idmod
Copy link
Collaborator

There is known issue about build-docs. Other than that everything looks good

@shchen-idmod shchen-idmod merged commit 95e6c97 into dev Feb 21, 2023
@shchen-idmod shchen-idmod deleted the 1810-fix branch February 1, 2024 21:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants