diff --git a/.gitignore b/.gitignore index 9d11cc60caab92254eaa92d86136696e4029f89b..34a377993555fc1491405a518701a1e1fa5a546c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ script.sh temp.sh template Python_CLI/examples/lamec.out +__pycache__ +form_schema.json diff --git a/.gitlab/merge_request_templates/new_jobscript_contribution_review_checklist.md b/.gitlab/merge_request_templates/new_jobscript_contribution_review_checklist.md new file mode 100644 index 0000000000000000000000000000000000000000..4b2baf6c9ff92055e51c6f5dc14bbf303317ad26 --- /dev/null +++ b/.gitlab/merge_request_templates/new_jobscript_contribution_review_checklist.md @@ -0,0 +1,23 @@ +# New Jobscript Template Contribution Review Checklist + +## General Information + +- **Author**: [Author's name] +- **Reviewer**: [Reviewer's name] +- **Issue Reference**: [Link to related issue number] +- **Overview**: Which HPC system and what software/framework/library is the + jobscript template for, and what are the basic configuration options and + restrictions. + +--- + +## Contribution Review Checklist + +- [ ] Merge request contains link to the original issue(s). +- [ ] A valid directory for the system already existed and was not created as a + part of this merge request. +- [ ] A directory named after the software/framework/library has been created + in the dedicated system directory. +- [ ] The new directory contains a template file. +- [ ] Template is well structured and readable. +- [ ] The new directory contains a valid lamec.json file. diff --git a/README.md b/README.md index 1e7f913db1be5b8864f9d21e705ea8b877cfd170..ae2a582748e77efd3bc7adf1548512fe87256891 100644 --- a/README.md +++ b/README.md @@ -11,3 +11,21 @@ to see what systems and software are available. If you want to contribute or learn about the structure of our project, please read our [wiki](https://gitlab.jsc.fz-juelich.de/CoE-RAISE/FZJ/lamec-oa/-/wikis/Home). + +## Build and Run + +To build LAMEC, run: + +``` +python3 lamec.py build +``` + +This command creates `form-schema.json` that is used for input control +for the front-end. + +You can test LAMEC locally using the built-in PHP web server: + +``` +php -S localhost:<port> +``` +>>>>>>> working diff --git a/Web_App/2023-10-17/index.php b/Web_App/2023-10-17/index.php deleted file mode 100644 index 4436c472045f3f0b459b13236a9c74fdeb41b9c2..0000000000000000000000000000000000000000 --- a/Web_App/2023-10-17/index.php +++ /dev/null @@ -1,250 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - - // Read configuration data from JSON file - $filename = "lamec_config.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = preg_replace("/\r|\n/", "", $config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // Get json string with configuration data - var json_config = JSON.parse('<?=$config_json_str?>'); - - // Reference form select objects - var sys_sel = document.getElementById("sys"); - var par_sel = document.getElementById("par"); - var sw_sel = document.getElementById("sw"); - - // Method to populate the partitions form select element - function getPartitions() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.partitions, function(p_key, partition) { - par_sel.options[par_sel.options.length] = new Option(partition, partition); - }); - } - }); - } - - // Method to populate the software form select element - function getSoftware() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.software, function(p_key, software) { - sw_sel.options[sw_sel.options.length] = new Option(software, software); - }); - } - }); - } - - // Method to add the other input fields for this system - function getFields() { - // Remove the input fields present - $("#additionalFields").empty(); - - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.fields, function(p_key, field) { - new_input = '<div class="mb-3"><label for="'; - new_input += field.fieldname; - new_input += '" class="form-label"><b>'; - new_input += field.name; - new_input += '</b></label><div id="'; - new_input += field.fieldname; - new_input += 'Help" class="form-text">'; - new_input += field.description; - new_input += '</div>'; - - if(field.type == 'string') { - new_input += '<input type="text" placeholder="' + field.placeholder + '" '; - } - else if(field.type == 'number') { - new_input += '<input type="number" min="' + field.min + '" max="' + field.max + '" '; - new_input += 'value="' + field.default + '" '; - } - - new_input += 'name="' + field.fieldname + '" '; - new_input += 'aria-describedby="' + field.fieldname + '" '; - new_input += 'class="form-control">'; - new_input += '</div>'; - $("#additionalFields").append(new_input); - }); - } - }); - } - - // Method to update link to system ducomentation - function updateSystemDocumentation() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if(system.name == selected_system) { - if(!system.documentation) { - // No documentation link available - hide system documentation line - $("#system-documentation").hide(); - } - else { - $("#system-name").text(system.name); - $("#system-documentation-url").attr("href", system.documentation); - $("#system-documentation").show(); - } - } - }); - } - - // Populate the system form select element with available systems and - // create a link to the system documentation of the first system - $.each(json_config.systems, function(key, system) { - sys_sel.options[sys_sel.options.length] = new Option(system.name, system.name); - }); - updateSystemDocumentation(); - - // Populate the partition and software form select elements and insert input fields - getPartitions(); - getSoftware(); - getFields(); - - // Capture the onChange event of the system form select element and update - // the available partitions accordingly and clear the software select element - sys_sel.onchange = function() { - par_sel.length = 0; - sw_sel.length = 0; - - updateSystemDocumentation(); - - getPartitions(); - getSoftware(); - getFields(); - - } - } -</script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - $config = json_decode($config_json, true); - - // Check input data, and replace any empty values with default values, if specified - foreach($config["systems"] as $system) { - if($system["name"] == $_POST["sys"]) { - foreach($system["fields"] as $field) { - if(array_key_exists("default", $field) && $_POST[$field["fieldname"]] == "") { - $_POST[$field["fieldname"]] = $field["default"]; - } - } - break; - } - } - - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-1"> - <label for="sys" class="form-label"><b>System</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-select" aria-describedby="sysHelp"></select> - </div> - - <div class="mb-1" id="system-documentation"> - <small class="text-body-secondary"> - <span id="system-name">System name</span> - <a id="system-documentation-url" href="#" target="_blank">documentation</a> - <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16"> - <path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/> - <path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/> - </svg> - </small> - </div> - - <div class="mb-3 mt-3"> - <label for="par" class="form-label"><b>Partition</b></label> - <div id="sysHelp" class="form-text">Select the partition on which you want to submit your job.</div> - <select name="par" id="par" class="form-select" aria-describedby="sysHelp"></select> - </div> - - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-select" aria-describedby="swHelp"></select> - </div> - - <div id="additionalFields"></div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/2023-10-17/lamec_config.json b/Web_App/2023-10-17/lamec_config.json deleted file mode 100644 index 87cef7bb902d42e73975bf0bb870da2d6b68c1e0..0000000000000000000000000000000000000000 --- a/Web_App/2023-10-17/lamec_config.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "systems": [ - { - "name": "JURECA", - "documentation": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", - "partitions": ["dc-cpu", "dc-gpu-devel"], - "software": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "DEEP", - "documentation": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", - "partitions": ["dp-esb", "dp-dam"], - "software": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - - }, - { - "name": "JUWELS", - "documentation": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", - "partitions": ["develbooster", "develgpus", "gpus"], - "software": ["Pytorch-DDP"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "LUMI", - "documentation": "https://docs.lumi-supercomputer.eu/software/", - "partitions": ["dev-g", "small-g", "standard-g"], - "software": ["Pytorch-DDP"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "VEGA", - "documentation": "https://doc.vega.izum.si", - "partitions": ["cpu"], - "software": ["Basilisk"], - "fields": [ - { - "name": "Dummy field", - "description": "Just a dummy field for testing purposes.", - "type": "string", - "placeholder": "dummyString", - "fieldname": "dummy", - "default": "DUMMY_TEXT", - "arg": "dummy" - }, - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - } - ] -} \ No newline at end of file diff --git a/Web_App/2023-11-13/index.php b/Web_App/2023-11-13/index.php deleted file mode 100644 index d49c9d1c8e9c149da61796d079caafb60c45a6e2..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-13/index.php +++ /dev/null @@ -1,422 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "lamec_config_new.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - $config = json_decode($config_json, true); - - // Check input data, and replace any empty values with default values, if specified - // OLD CODE - TO BE CHANGED TO INTERFACE WITH LAMEC - /** - foreach($config["systems"] as $system) { - if($system["name"] == $_POST["sys"]) { - foreach($system["fields"] as $field) { - if(array_key_exists("default", $field) && $_POST[$field["fieldname"]] == "") { - $_POST[$field["fieldname"]] = $field["default"]; - } - } - break; - } - } - **/ - - /** - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - **/ - - // For testing purposes - $output = var_export($_REQUEST, true); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/2023-11-13/lamec_config_new.json b/Web_App/2023-11-13/lamec_config_new.json deleted file mode 100644 index 0b9bc8ea045da3f7e9f01578aa5a796f83bae0a0..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-13/lamec_config_new.json +++ /dev/null @@ -1,300 +0,0 @@ -{ - "fields": [ - { - "name": "system", - "type": "string", - "desc": "Select the computing system on which you want to submit your job.", - "restriction": { - "type": "option", - "value": [ - "deep", - "jureca", - "juwels", - "lumi", - "vega" - ] - } - }, - { - "name": "software", - "type": "string", - "desc": "Select the software that your job depends on.", - "restriction": { - "type": "option", - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["deep"], - "value": [ - "ddp", - "deepspeed", - "heat", - "horovod" - ] - }, - { - "key": ["jureca"], - "value": [ - "ddp", - "deepspeed", - "heat", - "horovod" - ] - }, - { - "key": ["lumi"], - "value": ["ddp"] - }, - { - "key": ["vega"], - "value": ["basilisk"] - } - ] - } - } - } - }, - { - "name": "partition", - "desc": "Specify the partition for your job.", - "type": "string", - "restriction": { - "type": ["option"], - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["deep"], - "value": [ - "dp-esb", - "dp-dam" - ] - }, - { - "key": ["jureca"], - "value": [ - "dc-cpu", - "dc-gpu", - "dc-cpu-bigmem", - "dc-gpu-devel", - "dc-cpu-devel", - "dc-gpu-devel" - ] - }, - { - "key": ["juwels"], - "value": [ - "batch", - "mem192", - "devel", - "gpus", - "develgpus", - "booster", - "develbooster" - ] - }, - { - "key": ["lumi"], - "value": [ - "standard-g", - "standard", - "dev-g", - "debug", - "small-g", - "small", - "largemem" - ] - }, - { - "key": ["vega"], - "value": [ - "dev", - "cpu", - "longcpu", - "gpu", - "largemem" - ] - } - ] - } - } - } - }, - { - "name": "number_of_nodes", - "desc": "Specify the number of nodes.", - "type": "number", - "restriction": { - "type": ["range"], - "value": { - "depends_on": { - "fields": ["system", "partition"], - "resolution": [ - { - "key": ["deep", "dp-esb"], - "value": [1, 75] - }, - { - "key": ["deep", "dp-dam"], - "value": [1, 16] - }, - { - "key": ["jureca", "dc-cpu"], - "value": [1, 128] - }, - { - "key": ["jureca", "dc-gpu"], - "value": [1, 24] - }, - { - "key": ["jureca", "dc-cpu-bigmem"], - "value": [1, 48] - }, - { - "key": ["jureca", "dc-cpu-devel"], - "value": [1, 4] - }, - { - "key": ["jureca", "dc-gpu-devel"], - "value": [1, 4] - }, - { - "key": ["juwels", "batch"], - "value": [1, 1024] - }, - { - "key": ["juwels", "mem192"], - "value": [1, 64] - }, - { - "key": ["juwels", "devel"], - "value": [1, 8] - }, - { - "key": ["juwels", "gpus"], - "value": [1, 46] - }, - { - "key": ["juwels", "develgpus"], - "value": [1, 2] - }, - { - "key": ["juwels", "booster"], - "value": [1, 384] - }, - { - "key": ["juwels", "develbooster"], - "value": [1, 4] - }, - { - "key": ["lumi", "standard-g"], - "value": [1, 1024] - }, - { - "key": ["lumi", "standard"], - "value": [1, 512] - }, - { - "key": ["lumi", "dev-g"], - "value": [1, 32] - }, - { - "key": ["lumi", "debug"], - "value": [1, 4] - }, - { - "key": ["lumi", "small-g"], - "value": [1, 4] - }, - { - "key": ["lumi", "small"], - "value": [1, 4] - }, - { - "key": ["lumi", "largemem"], - "value": [1, 1] - }, - { - "key": ["vega", "dev"], - "value": [1, 8] - }, - { - "key": ["vega", "cpu"], - "value": [1, 960] - }, - { - "key": ["vega", "longcpu"], - "value": [1, 6] - }, - { - "key": ["vega", "gpu"], - "value": [1, 60] - }, - { - "key": ["vega", "largemem"], - "value": [1, 192] - } - ] - } - } - }, - "default": 1 - }, - { - "name": "account", - "type": "string", - "desc": "Specify the account for your job." - }, - { - "name": "executable", - "type": "string", - "desc": "Specify an executable for your job.", - "default": "app" - }, - { - "name": "dummy1", - "type": "string", - "desc": "Dummy field for testing, only shown when system is 'jureca'.", - "scope": [ - { - "fields": ["system"], - "values": [ - ["jureca"] - ] - } - ] - }, - { - "name": "dummy2", - "type": "string", - "desc": "Only shown when system is 'jureca' or 'deep' and software is 'ddp'.", - "scope": [ - { - "fields": ["system", "software"], - "values": [ - ["deep", "ddp"], - ["jureca", "ddp"] - ] - } - ] - } - ], - "documentation": { - "system": { - "jureca": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", - "deep": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", - "juwels": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", - "lumi": "https://docs.lumi-supercomputer.eu/software/", - "vega": "https://doc.vega.izum.si" - }, - "software": { - "ddp": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", - "horovod": "https://horovod.readthedocs.io/en/stable/", - "deepspeed": "https://deepspeed.readthedocs.io/en/latest/", - "heat": "https://heat.readthedocs.io/en/stable/" - } - } -} diff --git a/Web_App/2023-11-20/index.php b/Web_App/2023-11-20/index.php deleted file mode 100644 index 33c4c4436437d8de626a0a4b21b052bc87a7a630..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-20/index.php +++ /dev/null @@ -1,416 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "lamec_config_new.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - // $config = json_decode($config_json, true); - // Can be used if user input has to be verified - - - // - // Create JSON payload to pass on to LAMEC - // - $payload = array(); - foreach($_POST as $key => $val) { - if($val != "") { - $payload[$key] = $val; - } - } - $json_payload = json_encode($payload); - - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py ".$json_payload; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/index-thor.php b/Web_App/index-thor.php deleted file mode 100644 index 553349387a2f0fe117234055ede731addd60cf06..0000000000000000000000000000000000000000 --- a/Web_App/index-thor.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> -</head> -<body> - <div class="container my-5"> - <h4>Load AI Modules, Environments, and Containers (LAMEC) API </h4> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - putenv('PYTHONPATH="/var/www/apps/jsc/lamec-api"'); - $Phrase = "/domains/thorcurtis.com/public_html/test/lamec_ml.py gen -a " . $_POST["acc"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-3"> - <label for="sys" class="form-label"><b>System/Partition</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-control" aria-describedby="sysHelp"> - <option value="jureca">JURECA</option> - <option value="deep">DEEP</option> - <!-- - <option value="juwels">JUWELS</option> - --> - </select> - </div> - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-control" aria-describedby="swHelp"> - <option value="ddp">Pytorch-DDP</option> - <option value="horovod">Horovod</option> - <option value="deepspeed">DeepSpeed</option> - <option value="heat">HeAT</option> - </select> - </div> - <div class="mb-3"> - <label for="exe" class="form-label"><b>Executable</b></label> - <div id="exeHelp" class="form-text">Specify the executable of your application.</div> - <input type="text" name="exe" placeholder="./executable" class="form-control" aria-describedby="exeHelp"> - </div> - <div class="mb-3"> - <label for="nnodes" class="form-label"><b>Number of nodes</b></label> - <div id="nnodesHelp" class="form-text">Specify the number of nodes.</div> - <input type="number" name="nnodes" min="1" value="1" max="2400" class="form-control" aria-describedby="nnodesHelp"> - </div> - <div class="mb-3"> - <label for="acc" class="form-label"><b>Account</b></label> - <div id="accHelp" class="form-text">Specify the account for your job.</div> - <input type="text" name="acc" placeholder="accountName" class="form-control" aria-describedby="accHelp"> - </div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> -</body> -</html> \ No newline at end of file diff --git a/Web_App/index_tmp.php b/Web_App/index_tmp.php deleted file mode 100644 index 486c8258d679c0c03c535d6befb8424e3901b0bc..0000000000000000000000000000000000000000 --- a/Web_App/index_tmp.php +++ /dev/null @@ -1,134 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> -<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script> - var sys_Object = { - "JURECA": { - "dc-gpu": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "dc-gpu-devel":["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"] - }, - "DEEP": { - "dp-esb": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "dp-dam":["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"] - }, - "JUWELS": { - "develbooster": ["Pytorch-DDP"], - "develgpus":["Pytorch-DDP"], - "gpus":["Pytorch-DDP"] - }, - "LUMI": { - "dev-g": ["Pytorch-DDP"], - "small-g":["Pytorch-DDP"], - "standard-g":["Pytorch-DDP"] - }, - "VEGA": { - "cpu": ["Basilisk"] - } - } - -window.onload = function() { - var sys_sel = document.getElementById("sys"); - var par_sel = document.getElementById("par"); - var sw_sel = document.getElementById("sw"); - for (var x in sys_Object) { - sys_sel.options[sys_sel.options.length] = new Option(x, x); - } - sys_sel.onchange = function() { - //empty par and sw dropdowns - par_sel.length = 1; - sw_sel.length = 1; - //display correct values - for (var y in sys_Object[this.value]) { - par_sel.options[par_sel.options.length] = new Option(y, y); - } - } - par_sel.onchange = function() { - //empty sw dropdown - sw_sel.length = 1; - //display correct values - var z = sys_Object[sys_sel.value][this.value]; - for (var i = 0; i < z.length; i++) { - sw_sel.options[sw_sel.options.length] = new Option(z[i], z[i]); - } - } -} -</script> -</head> -<body> - <div class="container my-5"> - <h4>Load AI Modules, Environments, and Containers (LAMEC) API </h4> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-3"> - <label for="sys" class="form-label"><b>System</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-control" aria-describedby="sysHelp"> - <option value="" selected="selected">Please select system</option> - </select> - </div> - - <div class="mb-3"> - <label for="par" class="form-label"><b>Partition</b></label> - <div id="sysHelp" class="form-text">Select the partition on which you want to submit your job.</div> - <select name="par" id="par" class="form-control" aria-describedby="sysHelp"> - <option value="" selected="selected">please select partition</option> - </select> - </div> - - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-control" aria-describedby="swHelp"> - <option value="" selected="selected"> Please select software</option> - </select> - </div> - <div class="mb-3"> - <label for="exe" class="form-label"><b>Executable</b></label> - <div id="exeHelp" class="form-text">Specify the executable of your application.</div> - <input type="text" name="exe" placeholder="./executable" class="form-control" aria-describedby="exeHelp"> - </div> - <div class="mb-3"> - <label for="nnodes" class="form-label"><b>Number of nodes</b></label> - <div id="nnodesHelp" class="form-text">Specify the number of nodes.</div> - <input type="number" name="nnodes" min="1" value="1" max="2400" class="form-control" aria-describedby="nnodesHelp"> - </div> - <div class="mb-3"> - <label for="acc" class="form-label"><b>Account</b></label> - <div id="accHelp" class="form-text">Specify the account for your job.</div> - <input type="text" name="acc" placeholder="accountName" class="form-control" aria-describedby="accHelp"> - </div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> -</body> -</html> diff --git a/Web_App/index_v1.php b/Web_App/index_v1.php deleted file mode 100644 index 122b545ce605bf37bc6e2668cf98ccbdb13a6b81..0000000000000000000000000000000000000000 --- a/Web_App/index_v1.php +++ /dev/null @@ -1,57 +0,0 @@ -<html> -<body> - -<h1>Load AI Modules, Environments, and Containers (LAMEC) API </h1> - - <form action="index.php", method="post"> - <label for="sys">System/Partition:</label> - <select name="sys" id="sys"> - <option value="jureca">JURECA</option> - <option value="deep">DEEP</option> - <!-- - <option value="juwels">JUWELS</option> - --> - </select> - <br><br> - <label for="sw">Software:</label> - <select name="sw" id="sw"> - <option value="ddp">Pytorch-DDP</option> - <option value="horovod">Horovod</option> - <option value="deepspeed">DeepSpeed</option> - <option value="heat">HeAT</option> - </select> - <br><br> - Executable: <input type="text" name="exe"> - <br><br> - number of nodes: <input type="text" name="nnodes"> - <br><br> - Account: <input type="text" name="acc"> - <br><br> - <!-- - Wall time: <input type="text" name = "wtime"> - <br><br> - <input type="submit"> - --> - <input name="Submit" type="submit" class="submitbtn" value="Submit" /> - </form> - <br> -<?php - -//ini_set('display_errors', 1); -//ini_set('display_startup_errors', 1); -//error_reporting(E_ALL); -putenv('PYTHONPATH="/var/www/apps/jsc/lamec-api"'); - -if (isset( $_POST['Submit'])) -{ -$Phrase = "/var/www/apps/jsc/lamec-api/lamec_ml.py gen -a " . $_POST["acc"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; -//echo $Phrase; -$command = escapeshellcmd($Phrase); -$output = shell_exec($command); -echo $output; -} - -?> - -</body> -</html> diff --git a/about.php b/about.php new file mode 100644 index 0000000000000000000000000000000000000000..fc2df8924dd0354af2500c51cb07e234c277b75a --- /dev/null +++ b/about.php @@ -0,0 +1,6 @@ +<?php +include 'render.php'; +$active = 'about'; +$content = loadFragment('html/about.html'); +include 'base.php'; +?> diff --git a/base.php b/base.php new file mode 100644 index 0000000000000000000000000000000000000000..ba6e1cf1f22ba61112c116e4b4de83f3df60b948 --- /dev/null +++ b/base.php @@ -0,0 +1,158 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <meta name="viewport" + content="width=device-width, initial-scale=1, shrink-to-fit=no"> + + <!-- LOAD Highlight CSS --> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/github.min.css"> + + <!-- LOAD Bootstrap CSS --> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" + rel="stylesheet" + integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" + crossorigin="anonymous"> + + <?php if ($active == 'status'): ?> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" + crossorigin="anonymous"> + <?php endif; ?> + + <style> + .h-color { + color: rgb(4,132,196); + } + .w-980p { + max-width: 980px; + } + #jobscript-output { + font-family: monospace, monospace; + } + </style> + + <?php if ($active == 'form' || $active == 'status'): ?> + <!-- LOAD jQuery --> + <script src="https://code.jquery.com/jquery-3.7.1.min.js" + integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" + crossorigin="anonymous"> + </script> + <?php endif; ?> + + <!-- LOAD Popper --> + <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" + integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" + crossorigin="anonymous"> + </script> + + <!-- LOAD Bootstrap JS --> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" + integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" + crossorigin="anonymous"> + </script> + + <!-- LOAD Hightlight JS --> + <!-- Include the Highlight.js library --> + <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script> + <!-- Initialize Highlight.js --> + <script>hljs.highlightAll();</script> + + <?php if ($active == 'form'): ?> + <script src="js/form.js"></script> + <?php endif; ?> + + <?php if ($active == 'status'): ?> + <script src="js/status.js"></script> + <?php endif; ?> + + </head> + + <body class="d-flex flex-column min-vh-100"> + + <!-- BEGIN Header --> + <header> + + <!-- BEGIN Logo --> + <div class="container text-center mt-4 mb-4"> + <a href="https://www.coe-raise.eu" target="_blank"> + <img src="images/logo.png" + height="160" + alt="Raise Logo" + loading="lazy"> + </a> + </div> + <!-- END Logo --> + + <!-- BEGIN Navigation Bar --> + <nav class="navbar navbar-light navbar-expand-sm navbar-light bg-light"> + <div class="container justify-content-center w-980p"> + <!-- + <a href="about.php" class="navbar-brand h-color"> + LAMEC + </a> + --> + <button class="navbar-toggler" + type="button" + data-bs-toggle="collapse" + data-bs-target="#navbarNav" + aria-controls="navbarNav" + aria-expanded="false" + aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + <div class="collapse navbar-collapse flex-grow-0" id="navbarNav"> + <ul class="navbar-nav"> + <li class="nav-item"> + <a href="about.php" + class="nav-link <?php echo ($active == 'about' ? 'active' : ''); ?>"> + <!-- Home --> + About + </a> + </li> + <li class="nav-item"> + <a href="index.php" + class="nav-link <?php echo ($active == 'form' ? 'active' : ''); ?>"> + Jobscript Generator + </a> + </li> + <!-- <li class="nav-item"> + <a href="status.php" + class="nav-link <?php echo ($active == 'status' ? 'active' : ''); ?>"> + Status + </a> + </li> --> + </ul> + </div> + </div> + </nav> + <!-- END Navigation Bar --> + + </header> + <!-- END Header --> + + <!-- BEGIN Main Section --> + <main id="main-section" class="container my-4 w-980p"> + <?php echo $content ?> + </main> + <!-- END Main Section --> + + <!-- BEGIN Footer --> + <footer class="mt-auto py-3 bg-light"> + <div class="container text-center justify-content-center w-980p"> + <span class="text-body-secondary"> + <div class="py-3"> + The + <a href="https://www.coe-raise.eu" target"_blank"> + CoE RAISE project + </a> + has received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> + <div class="py-2">©2021 CoE RAISE.</div> + </span> + </div> + </footer> + <!-- END Footer --> + + </body> +</html> diff --git a/scripts/cteamd_ddp/DDP_startscript.sh b/contrib/cteamd_ddp/DDP_startscript.sh similarity index 100% rename from scripts/cteamd_ddp/DDP_startscript.sh rename to contrib/cteamd_ddp/DDP_startscript.sh diff --git a/scripts/cteamd_ddp/README.md b/contrib/cteamd_ddp/README.md similarity index 100% rename from scripts/cteamd_ddp/README.md rename to contrib/cteamd_ddp/README.md diff --git a/scripts/cteamd_ddp/createENV.sh b/contrib/cteamd_ddp/createENV.sh similarity index 100% rename from scripts/cteamd_ddp/createENV.sh rename to contrib/cteamd_ddp/createENV.sh diff --git a/scripts/cteamd_ddp/installWheels.sh b/contrib/cteamd_ddp/installWheels.sh similarity index 100% rename from scripts/cteamd_ddp/installWheels.sh rename to contrib/cteamd_ddp/installWheels.sh diff --git a/scripts/cteamd_ddp/lamec.json b/contrib/cteamd_ddp/lamec.json similarity index 100% rename from scripts/cteamd_ddp/lamec.json rename to contrib/cteamd_ddp/lamec.json diff --git a/scripts/cteamd_ddp/reqs.txt b/contrib/cteamd_ddp/reqs.txt similarity index 100% rename from scripts/cteamd_ddp/reqs.txt rename to contrib/cteamd_ddp/reqs.txt diff --git a/scripts/cteamd_deepspeed/DS_config.json b/contrib/cteamd_deepspeed/DS_config.json similarity index 100% rename from scripts/cteamd_deepspeed/DS_config.json rename to contrib/cteamd_deepspeed/DS_config.json diff --git a/scripts/cteamd_deepspeed/DS_startscript.sh b/contrib/cteamd_deepspeed/DS_startscript.sh similarity index 100% rename from scripts/cteamd_deepspeed/DS_startscript.sh rename to contrib/cteamd_deepspeed/DS_startscript.sh diff --git a/scripts/cteamd_deepspeed/README.md b/contrib/cteamd_deepspeed/README.md similarity index 100% rename from scripts/cteamd_deepspeed/README.md rename to contrib/cteamd_deepspeed/README.md diff --git a/scripts/cteamd_deepspeed/createENV.sh b/contrib/cteamd_deepspeed/createENV.sh similarity index 100% rename from scripts/cteamd_deepspeed/createENV.sh rename to contrib/cteamd_deepspeed/createENV.sh diff --git a/scripts/cteamd_deepspeed/installWheels.sh b/contrib/cteamd_deepspeed/installWheels.sh similarity index 100% rename from scripts/cteamd_deepspeed/installWheels.sh rename to contrib/cteamd_deepspeed/installWheels.sh diff --git a/scripts/cteamd_deepspeed/lamec.json b/contrib/cteamd_deepspeed/lamec.json similarity index 100% rename from scripts/cteamd_deepspeed/lamec.json rename to contrib/cteamd_deepspeed/lamec.json diff --git a/scripts/cteamd_deepspeed/reqs.txt b/contrib/cteamd_deepspeed/reqs.txt similarity index 100% rename from scripts/cteamd_deepspeed/reqs.txt rename to contrib/cteamd_deepspeed/reqs.txt diff --git a/scripts/cteamd_heat/HeAT_startscript.sh b/contrib/cteamd_heat/HeAT_startscript.sh similarity index 100% rename from scripts/cteamd_heat/HeAT_startscript.sh rename to contrib/cteamd_heat/HeAT_startscript.sh diff --git a/scripts/cteamd_heat/README.md b/contrib/cteamd_heat/README.md similarity index 100% rename from scripts/cteamd_heat/README.md rename to contrib/cteamd_heat/README.md diff --git a/scripts/cteamd_heat/createENV.sh b/contrib/cteamd_heat/createENV.sh similarity index 100% rename from scripts/cteamd_heat/createENV.sh rename to contrib/cteamd_heat/createENV.sh diff --git a/scripts/cteamd_heat/installWheels.sh b/contrib/cteamd_heat/installWheels.sh similarity index 100% rename from scripts/cteamd_heat/installWheels.sh rename to contrib/cteamd_heat/installWheels.sh diff --git a/scripts/cteamd_heat/lamec.json b/contrib/cteamd_heat/lamec.json similarity index 100% rename from scripts/cteamd_heat/lamec.json rename to contrib/cteamd_heat/lamec.json diff --git a/scripts/cteamd_heat/reqs.txt b/contrib/cteamd_heat/reqs.txt similarity index 100% rename from scripts/cteamd_heat/reqs.txt rename to contrib/cteamd_heat/reqs.txt diff --git a/scripts/cteamd_horovod/Hor_startscript.sh b/contrib/cteamd_horovod/Hor_startscript.sh similarity index 100% rename from scripts/cteamd_horovod/Hor_startscript.sh rename to contrib/cteamd_horovod/Hor_startscript.sh diff --git a/scripts/cteamd_horovod/README.md b/contrib/cteamd_horovod/README.md similarity index 100% rename from scripts/cteamd_horovod/README.md rename to contrib/cteamd_horovod/README.md diff --git a/scripts/cteamd_horovod/createENV.sh b/contrib/cteamd_horovod/createENV.sh similarity index 100% rename from scripts/cteamd_horovod/createENV.sh rename to contrib/cteamd_horovod/createENV.sh diff --git a/scripts/cteamd_horovod/installWheels.sh b/contrib/cteamd_horovod/installWheels.sh similarity index 100% rename from scripts/cteamd_horovod/installWheels.sh rename to contrib/cteamd_horovod/installWheels.sh diff --git a/scripts/cteamd_horovod/lamec.json b/contrib/cteamd_horovod/lamec.json similarity index 100% rename from scripts/cteamd_horovod/lamec.json rename to contrib/cteamd_horovod/lamec.json diff --git a/scripts/cteamd_horovod/reqs.txt b/contrib/cteamd_horovod/reqs.txt similarity index 100% rename from scripts/cteamd_horovod/reqs.txt rename to contrib/cteamd_horovod/reqs.txt diff --git a/scripts/juwels_turbulence/Autoencoder_Turbulence.py b/contrib/juwels_turbulence/Autoencoder_Turbulence.py similarity index 100% rename from scripts/juwels_turbulence/Autoencoder_Turbulence.py rename to contrib/juwels_turbulence/Autoencoder_Turbulence.py diff --git a/scripts/juwels_turbulence/Autoencoder_Turbulence_PINNs.py b/contrib/juwels_turbulence/Autoencoder_Turbulence_PINNs.py similarity index 100% rename from scripts/juwels_turbulence/Autoencoder_Turbulence_PINNs.py rename to contrib/juwels_turbulence/Autoencoder_Turbulence_PINNs.py diff --git a/scripts/juwels_turbulence/Autoencoder_Turbulence_horv.py b/contrib/juwels_turbulence/Autoencoder_Turbulence_horv.py similarity index 100% rename from scripts/juwels_turbulence/Autoencoder_Turbulence_horv.py rename to contrib/juwels_turbulence/Autoencoder_Turbulence_horv.py diff --git a/scripts/juwels_turbulence/Autoencoder_Turbulence_olddata.py b/contrib/juwels_turbulence/Autoencoder_Turbulence_olddata.py similarity index 100% rename from scripts/juwels_turbulence/Autoencoder_Turbulence_olddata.py rename to contrib/juwels_turbulence/Autoencoder_Turbulence_olddata.py diff --git a/scripts/juwels_turbulence/Autoencoder_Turbulence_serial.py b/contrib/juwels_turbulence/Autoencoder_Turbulence_serial.py similarity index 100% rename from scripts/juwels_turbulence/Autoencoder_Turbulence_serial.py rename to contrib/juwels_turbulence/Autoencoder_Turbulence_serial.py diff --git a/scripts/juwels_turbulence/CAE_loss_serial_vs_par.pdf b/contrib/juwels_turbulence/CAE_loss_serial_vs_par.pdf similarity index 100% rename from scripts/juwels_turbulence/CAE_loss_serial_vs_par.pdf rename to contrib/juwels_turbulence/CAE_loss_serial_vs_par.pdf diff --git a/scripts/juwels_turbulence/CAE_serial.pdf b/contrib/juwels_turbulence/CAE_serial.pdf similarity index 100% rename from scripts/juwels_turbulence/CAE_serial.pdf rename to contrib/juwels_turbulence/CAE_serial.pdf diff --git a/scripts/juwels_turbulence/startScript b/contrib/juwels_turbulence/startScript similarity index 100% rename from scripts/juwels_turbulence/startScript rename to contrib/juwels_turbulence/startScript diff --git a/scripts/juwels_turbulence/startScript_horovod b/contrib/juwels_turbulence/startScript_horovod similarity index 100% rename from scripts/juwels_turbulence/startScript_horovod rename to contrib/juwels_turbulence/startScript_horovod diff --git a/scripts/juwels_turbulence/startScript_serial b/contrib/juwels_turbulence/startScript_serial similarity index 100% rename from scripts/juwels_turbulence/startScript_serial rename to contrib/juwels_turbulence/startScript_serial diff --git a/scripts/pizda_ddp/DDP_startscript b/contrib/pizda_ddp/DDP_startscript similarity index 100% rename from scripts/pizda_ddp/DDP_startscript rename to contrib/pizda_ddp/DDP_startscript diff --git a/scripts/pizda_ddp/createENV.sh b/contrib/pizda_ddp/createENV.sh similarity index 100% rename from scripts/pizda_ddp/createENV.sh rename to contrib/pizda_ddp/createENV.sh diff --git a/scripts/pizda_ddp/lamec.json b/contrib/pizda_ddp/lamec.json similarity index 100% rename from scripts/pizda_ddp/lamec.json rename to contrib/pizda_ddp/lamec.json diff --git a/scripts/pizda_ddp/reqs.txt b/contrib/pizda_ddp/reqs.txt similarity index 100% rename from scripts/pizda_ddp/reqs.txt rename to contrib/pizda_ddp/reqs.txt diff --git a/Web_App/.gitkeep b/contrib/rudens_ddp/.gitkeep similarity index 100% rename from Web_App/.gitkeep rename to contrib/rudens_ddp/.gitkeep diff --git a/scripts/rudens_ddp/rtu_run.sh b/contrib/rudens_ddp/rtu_run.sh similarity index 100% rename from scripts/rudens_ddp/rtu_run.sh rename to contrib/rudens_ddp/rtu_run.sh diff --git a/scripts/rudens_ddp/rtu_run_schedule.sh b/contrib/rudens_ddp/rtu_run_schedule.sh similarity index 100% rename from scripts/rudens_ddp/rtu_run_schedule.sh rename to contrib/rudens_ddp/rtu_run_schedule.sh diff --git a/Web_App/2023-10-17/.gitkeep b/contrib/vsc_ddp/.gitkeep similarity index 100% rename from Web_App/2023-10-17/.gitkeep rename to contrib/vsc_ddp/.gitkeep diff --git a/scripts/vsc_ddp/dam_ex.job b/contrib/vsc_ddp/dam_ex.job similarity index 100% rename from scripts/vsc_ddp/dam_ex.job rename to contrib/vsc_ddp/dam_ex.job diff --git a/scripts/vsc_ddp/dam_tune_ex.job b/contrib/vsc_ddp/dam_tune_ex.job similarity index 100% rename from scripts/vsc_ddp/dam_tune_ex.job rename to contrib/vsc_ddp/dam_tune_ex.job diff --git a/scripts/vsc_ddp/raise_nn.def b/contrib/vsc_ddp/raise_nn.def similarity index 100% rename from scripts/vsc_ddp/raise_nn.def rename to contrib/vsc_ddp/raise_nn.def diff --git a/scripts/vsc_ddp/wice_ex.job b/contrib/vsc_ddp/wice_ex.job similarity index 100% rename from scripts/vsc_ddp/wice_ex.job rename to contrib/vsc_ddp/wice_ex.job diff --git a/data.php b/data.php new file mode 100644 index 0000000000000000000000000000000000000000..7d199972bade83516c7f7fdac3de7cf6e7265a97 --- /dev/null +++ b/data.php @@ -0,0 +1,8 @@ +<?php +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $raw_data = file_get_contents('php://input'); + $Phrase = "./lamec.py '$raw_data'"; + $output = shell_exec($Phrase); + echo $output; +} +?> diff --git a/data/form-schema.json b/data/form-schema.json new file mode 100644 index 0000000000000000000000000000000000000000..1cb083290b6440cc3bfc8864319069f00badd255 --- /dev/null +++ b/data/form-schema.json @@ -0,0 +1,747 @@ +{ + "fields": [ + { + "name": "system", + "desc": "Select the computing system on which you want to submit your job.", + "type": "string", + "restriction": { + "type": "option", + "value": [ + "Cyclone", + "DEEP", + "JURECA", + "JUWELS", + "LUMI", + "MockHPCSystem", + "VEGA" + ] + } + }, + { + "name": "software", + "desc": "Select the software your job depends on.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "Basilisk" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "MockSoftware" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "Basilisk", + "Horovod" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "HeAT", + "Pytorch-DDP" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + } + ] + } + } + } + }, + { + "name": "partition", + "desc": "Select the partition for your job.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "dev", + "cpu", + "longcpu", + "gpu", + "largemem" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "base" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "milan", + "skylake", + "nehalem", + "cpu", + "p100", + "a100", + "gpu" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "batch", + "mem192", + "devel", + "gpus", + "develgpus", + "booster", + "develbooster" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "standard-g", + "standard", + "dev-g", + "debug", + "small-g", + "small", + "largemem" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "dc-cpu", + "dc-cpu-bigmem", + "dc-cpu-devel", + "dc-gpu", + "dc-gpu-devel" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "dp-esb", + "dp-dam" + ] + } + ] + } + } + } + }, + { + "name": "nodes", + "desc": "Select the number of nodes.", + "type": "number", + "restriction": { + "type": "range", + "value": { + "depends_on": { + "fields": [ + "system", + "partition" + ], + "resolution": [ + { + "key": [ + "VEGA", + "dev" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "VEGA", + "cpu" + ], + "value": [ + 1, + 960 + ] + }, + { + "key": [ + "VEGA", + "longcpu" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "VEGA", + "gpu" + ], + "value": [ + 1, + 60 + ] + }, + { + "key": [ + "VEGA", + "largemem" + ], + "value": [ + 1, + 192 + ] + }, + { + "key": [ + "MockHPCSystem", + "base" + ], + "value": [ + 1, + 10 + ] + }, + { + "key": [ + "Cyclone", + "milan" + ], + "value": [ + 1, + 34 + ] + }, + { + "key": [ + "Cyclone", + "skylake" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "nehalem" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "cpu" + ], + "value": [ + 1, + 13 + ] + }, + { + "key": [ + "Cyclone", + "p100" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "Cyclone", + "a100" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "Cyclone", + "gpu" + ], + "value": [ + 1, + 16 + ] + }, + { + "key": [ + "JUWELS", + "batch" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "JUWELS", + "mem192" + ], + "value": [ + 1, + 64 + ] + }, + { + "key": [ + "JUWELS", + "devel" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "JUWELS", + "gpus" + ], + "value": [ + 1, + 46 + ] + }, + { + "key": [ + "JUWELS", + "develgpus" + ], + "value": [ + 1, + 2 + ] + }, + { + "key": [ + "JUWELS", + "booster" + ], + "value": [ + 1, + 384 + ] + }, + { + "key": [ + "JUWELS", + "develbooster" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "standard-g" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "LUMI", + "standard" + ], + "value": [ + 1, + 512 + ] + }, + { + "key": [ + "LUMI", + "dev-g" + ], + "value": [ + 1, + 32 + ] + }, + { + "key": [ + "LUMI", + "debug" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small-g" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "largemem" + ], + "value": [ + 1, + 1 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu" + ], + "value": [ + 1, + 128 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-bigmem" + ], + "value": [ + 1, + 48 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu" + ], + "value": [ + 1, + 24 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "DEEP", + "dp-esb" + ], + "value": [ + 1, + 75 + ] + }, + { + "key": [ + "DEEP", + "dp-dam" + ], + "value": [ + 1, + 16 + ] + } + ] + } + } + } + }, + { + "name": "account", + "desc": "Specify the account for your job.", + "type": "string", + "default": "Account", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + }, + { + "name": "executable", + "desc": "Specify an executable for your job.", + "type": "string", + "default": "app", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + } + ], + "documentation": { + "system": { + "JURECA": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", + "DEEP": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", + "JUWELS": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", + "LUMI": "https://docs.lumi-supercomputer.eu/software/", + "VEGA": "https://doc.vega.izum.si", + "Cyclone": "https://hpcf.cyi.ac.cy/documentation/" + }, + "software": { + "Pytorch-DDP": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", + "Horovod": "https://horovod.readthedocs.io/en/stable/", + "DeepSpeed": "https://deepspeed.readthedocs.io/en/latest/", + "HeAT": "https://heat.readthedocs.io/en/stable/" + } + } +} \ No newline at end of file diff --git a/data/status.json b/data/status.json new file mode 100644 index 0000000000000000000000000000000000000000..3d7e29e303179bb4b2c96fa84d6064706f91cf10 --- /dev/null +++ b/data/status.json @@ -0,0 +1,61 @@ +{ + "Cyclone": { + "Basilisk": { + }, + "Horovod": { + "passed": true + } + }, + "DEEP": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": true + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "JUWELS": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": false + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "JURECA": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": true + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "LUMI": { + "Pytorch-DDP": { + "passed": true + } + }, + "VEGA": { + "Basilisk": { + "passed": true + } + } +} diff --git a/examples/README.md b/examples/README.md deleted file mode 100644 index 1837209e7fa99f7fde3320c56f4da3ba0477f2e2..0000000000000000000000000000000000000000 --- a/examples/README.md +++ /dev/null @@ -1,23 +0,0 @@ -This directory contains: - -+ a mock-up command line interface for LAMEC (`mock_cli`) -+ two shell scripts (`create_example` and `update_example`) - that demonstrate the usage of said interface -+ two JSON files (`create_example.json` and `update_example.json`) - that show what the input to LAMEC should look like - -To use `mock_cli`, see the shell scripts mentioned above. -The `create_example` shell script will create an output file -named `lamec.out` (ignored by git). See also `mock_cli --help`. - -To use LAMEC with the JSON files, do: - -``` -cat create_example.json | ../lamec_ml -``` - -and - -``` -cat update_example.json | ../lamec_ml -``` diff --git a/examples/create_example b/examples/create_example deleted file mode 100755 index 22d758c3dcbf04550009fa9dd29a9d92f403dd7f..0000000000000000000000000000000000000000 --- a/examples/create_example +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname $0)" - -./mock_cli create \ - --account=johndoe@johndoe.com \ - --time=00:10:00 \ - --nodes=1 \ - deep ddp exe > lamec.out diff --git a/examples/create_example.json b/examples/create_example.json deleted file mode 100644 index 310ba13a7e1b7ef163c847b87794e4fe057cfc0f..0000000000000000000000000000000000000000 --- a/examples/create_example.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "account": "johndoe@johndoe.com", - "nodes": "1", - "partition": "dp-esb", - "system": "deep", - "software": "ddp", - "executable": "test.py" -} diff --git a/examples/mock_cli b/examples/mock_cli deleted file mode 100755 index 628fa78ef5a85de6f963607bea840dada1b3e9ae..0000000000000000000000000000000000000000 --- a/examples/mock_cli +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python3 -import json -import sys -import argparse -import subprocess - -""" - -This program is a mock command line interface for LAMEC. - -""" - -def update_args(args): - with open(args.script, 'r') as f: - script = f.read() - args.script = script - return json.dumps(vars(args), indent=4) - -def create_args(args): - return json.dumps(vars(args)) - -def send(json_str): - p = subprocess.run(['../lamec_ml', '{}'.format(json_str)], capture_output=True) - print(p.stdout.decode('utf-8'), end='') - -def main(): - cli = argparse.ArgumentParser(prog=sys.argv[0]) - - cli.add_argument('-o') - - sub = cli.add_subparsers() - - cli_create = sub.add_parser('create', help='create a jobscript') - cli_update = sub.add_parser('update', help='update a jobscript') - - cli_create.set_defaults(which='create') - cli_update.set_defaults(which='update') - - cli_create.add_argument('-a', '--account') - cli_create.add_argument('-N', '--nodes') - cli_create.add_argument('-t', '--time') - cli_create.add_argument('system', help='name of HPC system') - cli_create.add_argument('software', help='name of software library or framework') - cli_create.add_argument('exe', help='executable program') - - cli_update.add_argument('script', help='name of jobscript to update') - - args = cli.parse_args() - - if 'which' in vars(args): - if args.which == 'create': - send(create_args(args)) - elif args.which == 'update': - send(update_args(args)) - else: - cli.print_help(sys.stderr) - -if __name__ == "__main__": - main() diff --git a/examples/update_example b/examples/update_example deleted file mode 100755 index c6bfc7aafc7e4cb634edeaf119aabe0e7b9cd476..0000000000000000000000000000000000000000 --- a/examples/update_example +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname $0)" - -./mock_cli update "lamec.out" diff --git a/examples/update_example.json b/examples/update_example.json deleted file mode 100644 index 69c11a71342525019e9fae30393706c381209c98..0000000000000000000000000000000000000000 --- a/examples/update_example.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "which": "update", - "script": "#!/bin/bash\n#SBATCH --job-name=job\n#SBATCH --output=job.out\n#SBATCH --error=job.err\n#SBATCH --account=johndoe@johndoe.com\n#SBATCH --partition=dc-gpu\n#SBATCH --nodes=1\n#SBATCH --gpus-per-node=4\n#SBATCH --ntasks-per-node=1\n#SBATCH --cpus-per-task=1\n#SBATCH --exclusive\n#SBATCH --gres=gpu:4\n\n#MODULES BEGIN jureca ddp\nml --force purge\nml Stages/2022 NVHPC/22.3 ParaStationMPI/5.5.0-1-mt NCCL/2.12.7-1-CUDA-11.5 cuDNN/8.3.1.22-CUDA-11.5 Python/3.9.6 libaio/0.3.112 HDF5/1.12.1-serial mpi-settings/CUDA\n#MODULES END\n\nexport CUDA_VISIBLE_DEVICES=\"0,1,2,3\"\nsource /p/scratch/share/LAMEC/venv_DDP_JURECA/bin/activate\n\nsrun --cpu-bind=none bash -c \"torchrun \\\n --nnodes=$SLURM_NNODES \\\n --nproc_per_node=$SLURM_GPUS_PER_NODE \\\n --rdzv_id=$SLURM_JOB_ID \\\n --rdzv_conf=is_host=\\$(((SLURM_NODEID)) && echo 0 || echo 1) \\\n --rdzv_backend=c10d \\\n --rdzv_endpoint='$(scontrol show hostnames \"$SLURM_JOB_NODELIST\" | head -n 1)'i:29500 \\\ntest.py\"\n" -} diff --git a/html/about.html b/html/about.html new file mode 100644 index 0000000000000000000000000000000000000000..5cdabba83e1e756bad5c840060f20649f60e7738 --- /dev/null +++ b/html/about.html @@ -0,0 +1,31 @@ +<h1 class="display-6 mt-4 mb-5 h-color"> + <b>L</b>oad + <b>A</b>I + <b>M</b>odules, + <b>E</b>nvironments & + <b>C</b>ontainers<br> +</h1> +<section> + <p>The <strong>LAMEC</strong> API ( + <b>L</b>oad + <b>A</b>I + <b>M</b>odules, + <b>E</b>nvironments and + <b>C</b>ontainers) + is a tool that allows HPC developers and researchers to share their + configurations, setups and jobscripts of commonly used frameworks + and libraries, so they can be used to generate up to date + jobscripts. Take a look at the + <a href="index.php">jobscript generator</a> on this site + to see what systems and software are available. If you want to + contribute or learn about the structure of the project, please + read the + <a href="https://gitlab.jsc.fz-juelich.de/CoE-RAISE/FZJ/lamec-oa/-/wikis/LAMEC-Project-Overview" target="_blank"> + wiki + </a> + in the GitLab + <a href="https://gitlab.jsc.fz-juelich.de/CoE-RAISE/FZJ/lamec-oa" target="_blank"> + repository. + </a> + </p> +</section> diff --git a/html/form.html b/html/form.html new file mode 100644 index 0000000000000000000000000000000000000000..da453fae8bdf8c078fa7bc606a6b8e178eaaad4a --- /dev/null +++ b/html/form.html @@ -0,0 +1,6 @@ +<form action="index.php", method="post"> + <div id="formFields"></div> + <button type="submit" name="Submit" class="btn btn-primary mt-5"> + Generate jobscript + </button> +</form> diff --git a/html/output.html b/html/output.html new file mode 100644 index 0000000000000000000000000000000000000000..7dcbacf36c7372ce75cbd63f9d1a389cfcf5e469 --- /dev/null +++ b/html/output.html @@ -0,0 +1,24 @@ +<div class="mb-3"> + <!-- + <label for="output" class="form-label"><b>Your start script:</b></label> + <textarea id="jobscript-output" rows="20" class="form-control"><?php echo $output ?></textarea> + --> + <!-- <ol class="breadcrumb"> --> + <!-- <li class="breadcrumb-item">Systems</li> --> + <!-- <li class="breadcrumb-item">Software</li> --> + <!-- <li class="breadcrumb-item">Configure</li> --> + <!-- <li class="breadcrumb-item active">Jobscript</li> --> + <!-- </ol> --> + + <pre><code id="code" class="language-bash border"><?php echo $output ?></code></pre> + <button onclick="copyCode()"> + Copy + </button> +</div> +<script> + function copyCode() { + var element = document.getElementById("code"); + console.log(element.textContent); + navigator.clipboard.writeText(element.textContent); + } +</script> diff --git a/html/status.html b/html/status.html new file mode 100644 index 0000000000000000000000000000000000000000..793cba697c93c28c8d779ace111bbf6aa69f997c --- /dev/null +++ b/html/status.html @@ -0,0 +1,12 @@ +<table class="table table-striped table-bordered table-hover my-5"> + <thead> + <tr> + <th scope="col">System</th> + <th scope="col">Software</th> + <th scope="col">Status</th> + </tr> + </thead> + <tbody id="table-body"> + </tbody> +</table> + diff --git a/Web_App/2023-11-13/2021-01-Logo-RGB-RAISE_standard.png b/images/logo.png similarity index 100% rename from Web_App/2023-11-13/2021-01-Logo-RGB-RAISE_standard.png rename to images/logo.png diff --git a/index.php b/index.php index 1e976691749d5ded8c4aed9b41b42f235f601535..97e4c9cfcb2991653ff7bcab2427f53a36ebefa2 100644 --- a/index.php +++ b/index.php @@ -1,416 +1,32 @@ <?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "lamec_config_new.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); +include 'render.php'; + +if(isset( $_POST['Submit'])) { + // Convert JSON confid settings to array + // $config = json_decode($config_json, true); + // Can be used if user input has to be verified + + // + // Create JSON payload to pass on to LAMEC + // + $payload = array(); + foreach($_POST as $key => $val) { + if($val != "") { + $payload[$key] = $val; + } + } + $json_payload = json_encode($payload); + + // putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); + $Phrase = "./lamec.py '$json_payload'"; + // $command = escapeshellcmd($Phrase); + $output = shell_exec($Phrase); + $active = 'form'; + $content = loadFragment('html/output.html', ['output' => $output]); + include 'base.php'; +} else { + $active = 'form'; + $content = loadFragment('html/form.html'); + include 'base.php'; +} ?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - // $config = json_decode($config_json, true); - // Can be used if user input has to be verified - - - // - // Create JSON payload to pass on to LAMEC - // - $payload = array(); - foreach($_POST as $key => $val) { - if($val != "") { - $payload[$key] = $val; - } - } - $json_payload = json_encode($payload); - - // putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "./lamec '$json_payload'"; - // $command = escapeshellcmd($Phrase); - $output = shell_exec($Phrase); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/js/form.js b/js/form.js new file mode 100644 index 0000000000000000000000000000000000000000..d255bc3e583e31360ab224a786de50edb8eb3350 --- /dev/null +++ b/js/form.js @@ -0,0 +1,307 @@ +window.addEventListener("load", (event) => { + $.getJSON("data/form-schema.json", init); +}); + +function init(json_config) { + // Default html container name for fields + defaultFieldPosition = $("#formFields") + + // + // Set up the form dynamically with all fields from the + // LAMEC configuration + // + $.each(json_config.fields, function(key, field) { + // + // Add the header for the field, containing the field name + // and a description of the field + // + addFieldHeaderElement(field.name, field.desc); + + // + // Add an empty field element as specified in the JSON data. + // Check for the special case where field type is string, but there is + // a restriction of type 'option', in that case the field is SELECT. + // + fieldType = field.type; + if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { + fieldType = 'select'; + } + addFieldElement(field.name, fieldType); + + // + // Process the settings for the field that was created above and add + // the settings as a data attribute to each form field for later use. + // + if(field.restriction) { + $("#" + field.name).data("restriction", field.restriction); + } + if(field.scope) { + $("#" + field.name).data("scope", field.scope); + } + if(field.default) { + $("#" + field.name).data("default", field.default); + } + + // + // Check if there is documentation available for this field, and if there is then + // add it as a data attribute to the relevant form field for later reference, + // then add the html element. + // + if(json_config.documentation && json_config.documentation[field.name]) { + $("#" + field.name).data("documentation", json_config.documentation[field.name]); + addDocumentationElement(field.name); + } + + // + // Process this field's data and update the form element accordingly, + // taking into account all restrictions, dependencies and scope. + // + setFieldAttributes(field.name); + }); + + + // + // Adds the html header for a field. + // + function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { + new_field = '<div class="mt-4" '; + new_field += 'id="' + fieldName + 'Header" '; + new_field += '><label for="'; + new_field += fieldName; + new_field += '" class="form-label"><b>'; + new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); + new_field += '</b></label><div id="'; + new_field += fieldName; + new_field += 'Help" class="form-text mt-0 mb-1">'; + new_field += fieldDescription; + new_field += '</div></div>'; + fieldPosition.append(new_field); + } + + // + // Adds an empty field element. + // + function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { + new_field = '<div class="my-0" '; + new_field += 'id="' + fieldName + 'Element">'; + if(fieldType == 'select') { + new_field += '<select class="form-select" '; + } + else if(fieldType == 'number') { + new_field += '<input class="form-control" type="number" '; + } + else if(fieldType == 'string') { + new_field += '<input class="form-control" type="text" '; + } + + new_field += 'id="' + fieldName + '" '; + new_field += 'name="' + fieldName + '" '; + new_field += 'aria-describedby="' + fieldName + 'Help" >'; + + if(fieldType == 'select') { + new_field += '</select>'; + } + new_field += '</div>'; + fieldPosition.append(new_field); + } + + // + // Add an html documentation element. + // + function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { + new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; + new_field += '<small class="text-body-secondary">'; + new_field += '<span id="' + fieldName + '-name"></span> '; + new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; + new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; + new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; + new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; + new_field += '</svg></small></div>'; + fieldPosition.append(new_field); + } + + // + // Process the field's data and update the form element accordingly, + // taking into account all restrictions, dependencies and scope. + // + function setFieldAttributes(fieldName) { + fieldElement = $("#" + fieldName); + + if(fieldElement.data("scope")) { + // + // The field has a specific scope, show or hide + // the field accordingly. + // + if(isFieldWithinScope(fieldElement.data("scope"))) { + $("#" + fieldName + "Header").show(); + $("#" + fieldName + "Element").show(); + } + else { + $("#" + fieldName + "Header").hide(); + $("#" + fieldName + "Element").hide(); + } + } + + restriction = fieldElement.data("restriction"); + if(restriction) { + // + // Process the field's restrictions. + // + restrictionType = restriction.type; + + // + // The field is a select field, delete all options present + // and then repopulate the field, taking into account restrictions + // and dependencies. + // + if(restrictionType == 'option') { + $("#" + fieldName).length = 0; + } + + if(restriction.value.depends_on) { + dependantFields = restriction.value.depends_on.fields; + dependantResolution = restriction.value.depends_on.resolution; + + $.each(dependantResolution, function(index, resolution) { + // Track the number of resolutions that are met + resolutionCount = 0; + for(i=0; i<resolution.key.length; i++) { + if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { + // one resolution met + resolutionCount++; + } + else { + // a resolution not met, skip to next + // continue + return(true); + } + } + + if(resolutionCount == i) { + // All dependant resolutions met + if(restrictionType == 'range') { + fieldElement.attr("min", resolution.value[0]); + fieldElement.attr("max", resolution.value[1]); + fieldElement.val(resolution.value[0]); + } + else if(restrictionType == 'option') { + populateFieldElementOptions(fieldName, resolution.value); + } + // As all resolutions were met, no need to search further. + // break + return(false); + } + }); + } + else { + if(restrictionType == 'option') { + populateFieldElementOptions(fieldName, restriction.value); + } + else if (restrictionType == 'range'){ + fieldElement.attr("min", restriction.value[0]); + fieldElement.attr("max", restriction.value[1]); + fieldElement.val(restriction.value[0]); + } + } + } + + // Set defaut field value, if defined. + if(fieldElement.data("default")) { + fieldElement.val(fieldElement.data("default")); + } + + if(fieldElement.data("documentation")) { + // Show documentation if selected option has documentation available + updateDocumentation(fieldName); + } + } + + // + // Method to update link to documentation for selected option + // + function updateDocumentation(fieldName) { + let documentationFound = false; + $.each($("#" + fieldName).data("documentation"), function(key, val) { + if(document.getElementById(fieldName).value == key) { + $("#" + fieldName + "-name").text(key); + $("#" + fieldName + "-documentation-url").attr("href", val); + documentationFound = true; + // break + return(false); + } + }); + if(documentationFound) { + $("#" + fieldName + "-documentation").show(); + } + else { + $("#" + fieldName + "-documentation").hide(); + } + } + + // + // Method to pupolate the options of a select element + // + function populateFieldElementOptions(fieldName, fieldValues) { + sel_element = document.getElementById(fieldName); + sel_element.length = 0; + $.each(fieldValues, function(key, val) { + sel_element.options[sel_element.options.length] = new Option(val, val); + }); + } + + // + // Method to check if a field is within scope. + // + function isFieldWithinScope(fieldScope) { + let isWithinScope = false; + if(fieldScope) { + $.each(fieldScope, function(key, scope) { + $.each(scope.values, function(key, vals) { + let matchedVals = 0; + for(i = 0; i < vals.length; i++) { + if(vals[i] == document.getElementById(scope.fields[i]).value) { + matchedVals++; + } + else { + continue; + } + } + if(matchedVals == vals.length) { + isWithinScope = true; + return(false); + } + }) + }); + return(isWithinScope); + } + return(false); + } + + // + // Catch all changes to select elements and update other fields accordingly, + // based on the rules of dependencies, scope and available documentation + // + $(".form-select").on('change', function() { + changedField = this.name; + + // If field has documentation data, then it needs updating + if($("#" + changedField).data("documentation")) { + updateDocumentation(changedField); + } + + $.each(json_config.fields, function(key, field) { + if(field.scope) { + setFieldAttributes(field.name); + } + else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { + $.each(field.restriction.value.depends_on.fields, function(key, val) { + if(val == changedField) { + // Update the field, according to set dependencies + setFieldAttributes(field.name); + } + }); + } + }); + + }); +} diff --git a/js/status.js b/js/status.js new file mode 100644 index 0000000000000000000000000000000000000000..370c6ee3d068eac3c1ec382aefa9ff40e77653d6 --- /dev/null +++ b/js/status.js @@ -0,0 +1,31 @@ +window.addEventListener("load", (event) => { + $.getJSON("/data/status.json", init); +}); + +function passedIcon(passed) { + if (passed !== undefined) { + var color = passed ? 'green' : 'red'; + } else { + var color = 'grey'; + } + return `<i class="fa fa-solid fa-circle" style="color: ${color}"></i>`; +} + +function addTableElement(tableBody, system, software, passed) { + tableBody.append(` + <tr> + <td>${system}</td> + <td>${software}</td> + <td>${passedIcon(passed)}</td> + </tr> + `); +} + +function init(data) { + let tableBody = $("#table-body"); + $.each(data, (system, software_list) => { + $.each(software_list, (software, value) => { + addTableElement(tableBody, system, software, value.passed); + }); + }); +} diff --git a/lamec-cli.py b/lamec-cli.py new file mode 100755 index 0000000000000000000000000000000000000000..6fc0c8f743fa478e38ccd765550a07ed4ad9e487 --- /dev/null +++ b/lamec-cli.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +import http.client +import json +import argparse +import sys + +url = 'localhost:5000' + +def get_form_schema(): + endpoint = '/data/form-schema.json' + conn = http.client.HTTPConnection(url) + headers = { + 'Content-type': 'application/json' + } + conn.request('GET', endpoint, headers=headers) + response = conn.getresponse() + data = json.loads(response.read()) + conn.close() + return data + +def get_system_desc(data): + for field in data['fields']: + if field['name'] == 'system': + return field['desc'] + +def get_systems(data): + for field in data['fields']: + if field['name'] == 'system': + return field['restriction']['value'] + +def add_system_parsers(parser, data): + subparsers = parser.add_subparsers( + dest='system', + title='list of available systems', + metavar='SYSTEM', + help=get_system_desc(data), + ) + system_parsers = {} + for name in get_systems(data): + system_parsers[name] = subparsers.add_parser( + name, + help='', + ) + return system_parsers + +def get_software_desc(data): + for field in data['fields']: + if field['name'] == 'software': + return field['desc'] + +def add_software_parser(): + pass + +class CustomArgumentDefaultsHelpFormatter(argparse.ArgumentDefaultsHelpFormatter): + def _get_help_string(self, action): + help_str = action.help + if '%(default)' not in action.help: + if action.default is not None and action.default != argparse.SUPPRESS: + help_str += ' (default: %(default)s)' + return help_str + +def add_software_parsers(parser, system, data): + subparsers = parser.add_subparsers( + dest=f'software', + title='list of available software', + metavar='SOFTWARE', + description=get_software_desc(data), + help='' + ) + res = None + for field in data['fields']: + if field['name'] == 'software': + res = field['restriction']['value']['depends_on']['resolution'] + software = [] + for entry in res: + if system in entry['key']: + software = entry['value'] + for name in software: + subparser = subparsers.add_parser( + name, + help='', + formatter_class=CustomArgumentDefaultsHelpFormatter, + ) + ''' + subparser.add_argument( + '--output', + metavar='', + help='Write to FILE instead of stdout' + ) + ''' + group = subparser.add_argument_group(title='configuration') + for field in data['fields']: + if field['name'] != 'system' and field['name'] != 'software': + include = True + if 'scope' in field: + found = False + for value in field['scope'][0]['values']: + if system in value and name in value: + found = True + break + if not found: + include = False + if include: + arg = { + 'metavar': '\b', + 'help': field['desc'] + } + if 'default' not in field: + arg['required'] = True + else: + arg['default'] = field['default'] + group.add_argument( + f'--{field["name"]}', + **arg, + ) + +def post_request(data): + server = 'localhost:5000' + endpoint = '/data.php' + + json_data = json.dumps(data) + + conn = http.client.HTTPConnection(server) + + headers = { + 'Content-type': 'application/json', + 'Content-length': str(len(json_data)), + } + + conn.request('POST', endpoint, body=json_data, headers=headers) + response = conn.getresponse() + response_data = response.read() + conn.close() + return response_data + +def main(): + parser = argparse.ArgumentParser(prog=sys.argv[0]) + data = get_form_schema() + system_parsers = add_system_parsers(parser, data) + for name in system_parsers: + add_software_parsers(system_parsers[name], name, data) + args = parser.parse_args() + if not args.system: + parser.print_help() + sys.exit(1) + else: + if not vars(args)[f'software']: + system_parsers[args.system].print_help() + sys.exit(1) + + print(post_request(vars(args)).decode('ascii'), end='') + +if __name__ == '__main__': + main() diff --git a/lamec b/lamec.py similarity index 76% rename from lamec rename to lamec.py index 9acad2d8606556285e9e0ada0aeecdc9df7794fe..dac68757cc6ee0bcbc4e351eb843574177aa16c8 100755 --- a/lamec +++ b/lamec.py @@ -3,62 +3,37 @@ import sys import json import os +import re +import update +import http.client scriptpath = f'{sys.path[0]}/scripts' -def get_placeholders(template): - placeholders = [] - pattern = re.compile(r'%.[a-zA-Z0-9_:-]+%') - for x in re.findall(pattern, template): - p = x.replace('%', '') - if p not in placeholders: - placeholders.append(p) - return placeholders +def report(system, software, passed): + server = 'localhost:5000' + endpoint = '/data/status.json' -def get_template(system, software): - template_path = f'{scriptpath}/{system}/{software}/template.sh' - with open(template_path, 'r') as f: - return f.read() + data = { + 'system': system, + 'software': software, + 'passed': passed + } -def expand_template(data): - template = get_template(data['environment']['system'], - data['environment']['software']) - for key in data['environment']: - template = template.replace(f'%{key}%', data['environment'][key]) - return template + json_data = json.dumps(data) + + conn = http.client.HTTPConnection(server) + + headers = { + 'Content-type': 'application/json', + 'Content-length': str(len(json_data)) + } + + conn.request('POST', endpoint, body=json_data, headers=headers) + response = conn.getresponse() + response_data = response.read() + print(response_data) -def get_configuration(system, software): - configpath = f'{scriptpath}/{system}/{software}/config.json' - sysinfopath = f'{scriptpath}/{system}/sysinfo.json' - - try: - with open(configpath, 'r') as f: - data = json.load(f) - except: - data = {'environment': {}} - data['environment']['system'] = system - data['environment']['software'] = software - - try: - with open(sysinfopath, 'r') as f: - data['sysinfo'] = json.load(f) - except: - pass - - placeholders = get_placeholders(get_template(system, software)) - for p in placeholders: - if p not in data['environment']: - data['environment'][p] = None - return data - -def get_setup(request): - config = get_configuration(request['environment']['system'], - request['environment']['software']) - config['environment'].update(request['environment']) - config['jobscript'] = expand_template(config) - del config['sysinfo'] - del config['environment'] - return config + conn.close() class Module: """ @@ -202,18 +177,42 @@ def parse(args): outp = param_block + module_block + env_block + launch_block print(outp, end='') -def expand(args): +def get_placeholders(template): + placeholders = [] + pattern = re.compile(r'%.[a-zA-Z0-9_:-]+%') + for x in re.findall(pattern, template): + p = x.replace('%', '') + if p not in placeholders: + placeholders.append(p) + return placeholders + +def get_template(system, software): + # TODO: error handling + dirpath = f'{scriptpath}/{system}/{software}' + with open(f'{dirpath}/lamec.json', 'r') as f: + info = json.load(f) + if 'template' not in info: + return False + template_path = f'{dirpath}/{info["template"]}' + with open(template_path, 'r') as f: + return f.read() + +def expand(template, args): for key in args: - args['template'] = args['template'].replace(f'%{key}%', args[key]) - return args['template'] + template = template.replace(f'%{key}%', args[key]) + return template def main(): if len(sys.argv) == 1: args = json.load(sys.stdin) else: - args = json.loads(sys.argv[1]) + if len(sys.argv) > 1 and sys.argv[1] == 'build': + update.update_all() + return + else: + args = json.loads(sys.argv[1]) - path = os.path.join('scripts', f"{args['system']}_{args['software']}") + path = os.path.join(scriptpath, f"{args['system']}/{args['software']}") with open(os.path.join(path, 'lamec.json'), 'r') as f: config = json.load(f) if 'startscript' in config: @@ -221,9 +220,8 @@ def main(): args['startscript'] = f.read() parse(args) elif 'template' in config: - with open(os.path.join(path, config['template']), 'r') as f: - args['template'] = f.read() - print(expand(args), end='') + template = get_template(args['system'], args['software']) + print(expand(template, args), end='') if __name__ == '__main__': main() diff --git a/lamec_config_new.json b/lamec_config_new.json deleted file mode 100644 index cb194efe78e6b975b8c530567ce44f648f6790ac..0000000000000000000000000000000000000000 --- a/lamec_config_new.json +++ /dev/null @@ -1,280 +0,0 @@ -{ - "fields": [ - { - "name": "system", - "type": "string", - "desc": "Select the computing system on which you want to submit your job.", - "restriction": { - "type": "option", - "value": [ - "DEEP", - "JURECA", - "JUWELS", - "LUMI", - "VEGA", - "CYCLONE" - ] - } - }, - { - "name": "software", - "type": "string", - "desc": "Select the software that your job depends on.", - "restriction": { - "type": "option", - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["DEEP"], - "value": [ - "Pytorch-DDP", - "DeepSpeed", - "HeAT", - "Horovod" - ] - }, - { - "key": ["JURECA"], - "value": [ - "Pytorch-DDP", - "DeepSpeed", - "HeAT", - "Horovod" - ] - }, - { - "key": ["LUMI"], - "value": ["Pytorch-DDP","DeepSpeed","HeAT","Horovod"] - }, - { - "key": ["VEGA"], - "value": ["Basilisk"] - }, - { - "key": ["CYCLONE"], - "value": ["Horovod","Basilisk"] - }, - { - "key": ["JUWELS"], - "value": ["Pytorch-DDP","DeepSpeed","HeAT","Horovod"] - } - ] - } - } - } - }, - { - "name": "partition", - "desc": "Specify the partition for your job.", - "type": "string", - "restriction": { - "type": ["option"], - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["DEEP"], - "value": [ - "dp-esb", - "dp-dam" - ] - }, - { - "key": ["JURECA"], - "value": [ - "dc-gpu", - "dc-gpu-devel" - ] - }, - { - "key": ["JUWELS"], - "value": [ - "gpus", - "develgpus", - "booster", - "develbooster" - ] - }, - { - "key": ["LUMI"], - "value": [ - "standard-g", - "dev-g", - "small-g", - "largemem" - ] - }, - { - "key": ["CYCLONE"], - "value": [ - "cpu", - "gpu" - ] - }, - { - "key": ["VEGA"], - "value": [ - "dev", - "cpu", - "longcpu", - "largemem" - ] - } - ] - } - } - } - }, - { - "name": "nodes", - "desc": "Specify the number of nodes.", - "type": "number", - "restriction": { - "type": ["range"], - "value": { - "depends_on": { - "fields": ["system", "partition"], - "resolution": [ - { - "key": ["DEEP", "dp-esb"], - "value": [1, 75] - }, - { - "key": ["DEEP", "dp-dam"], - "value": [1, 16] - }, - { - "key": ["JURECA", "dc-cpu"], - "value": [1, 128] - }, - { - "key": ["JURECA", "dc-gpu"], - "value": [1, 24] - }, - { - "key": ["JURECA", "dc-cpu-bigmem"], - "value": [1, 48] - }, - { - "key": ["JURECA", "dc-cpu-devel"], - "value": [1, 4] - }, - { - "key": ["JURECA", "dc-gpu-devel"], - "value": [1, 4] - }, - { - "key": ["JUWELS", "batch"], - "value": [1, 1024] - }, - { - "key": ["JUWELS", "mem192"], - "value": [1, 64] - }, - { - "key": ["JUWELS", "devel"], - "value": [1, 8] - }, - { - "key": ["JUWELS", "gpus"], - "value": [1, 46] - }, - { - "key": ["JUWELS", "develgpus"], - "value": [1, 2] - }, - { - "key": ["JUWELS", "booster"], - "value": [1, 384] - }, - { - "key": ["JUWELS", "develbooster"], - "value": [1, 4] - }, - { - "key": ["LUMI", "standard-g"], - "value": [1, 1024] - }, - { - "key": ["LUMI", "standard"], - "value": [1, 512] - }, - { - "key": ["LUMI", "dev-g"], - "value": [1, 32] - }, - { - "key": ["LUMI", "debug"], - "value": [1, 4] - }, - { - "key": ["LUMI", "small-g"], - "value": [1, 4] - }, - { - "key": ["LUMI", "small"], - "value": [1, 4] - }, - { - "key": ["LUMI", "largemem"], - "value": [1, 1] - }, - { - "key": ["VEGA", "dev"], - "value": [1, 8] - }, - { - "key": ["VEGA", "cpu"], - "value": [1, 960] - }, - { - "key": ["VEGA", "longcpu"], - "value": [1, 6] - }, - { - "key": ["VEGA", "gpu"], - "value": [1, 60] - }, - { - "key": ["VEGA", "largemem"], - "value": [1, 192] - } - ] - } - } - }, - "default": 1 - }, - { - "name": "account", - "type": "string", - "desc": "Specify the account for your job.", - "default": "Account" - }, - { - "name": "executable", - "type": "string", - "desc": "Specify an executable for your job.", - "default": "app" - } - ], - "documentation": { - "system": { - "JURECA": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", - "DEEP": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", - "JUWELS": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", - "LUMI": "https://docs.lumi-supercomputer.eu/software/", - "VEGA": "https://doc.vega.izum.si", - "CYCLONE": "https://hpcf.cyi.ac.cy/documentation/" - }, - "software": { - "Pytorch-DDP": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", - "Horovod": "https://horovod.readthedocs.io/en/stable/", - "DeepSpeed": "https://deepspeed.readthedocs.io/en/latest/", - "HeAT": "https://heat.readthedocs.io/en/stable/" - } - } -} diff --git a/render.php b/render.php new file mode 100644 index 0000000000000000000000000000000000000000..3672cb08657832522b6817c1beedb2bf79cc3588 --- /dev/null +++ b/render.php @@ -0,0 +1,8 @@ +<?php +function loadFragment($filename, $variables = []) { + extract($variables); + ob_start(); + include $filename; + return ob_get_clean(); +} +?> diff --git a/scripts/CYCLONE_BASILISK/.gitkeep b/scripts/CYCLONE_BASILISK/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/scripts/CYCLONE_Horovod/.gitkeep b/scripts/CYCLONE_Horovod/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Web_App/2023-11-13/.gitkeep b/scripts/Cyclone/Basilisk/.gitkeep similarity index 100% rename from Web_App/2023-11-13/.gitkeep rename to scripts/Cyclone/Basilisk/.gitkeep diff --git a/scripts/CYCLONE_BASILISK/_script.sh b/scripts/Cyclone/Basilisk/_script.sh similarity index 100% rename from scripts/CYCLONE_BASILISK/_script.sh rename to scripts/Cyclone/Basilisk/_script.sh diff --git a/scripts/CYCLONE_BASILISK/lamec.json b/scripts/Cyclone/Basilisk/lamec.json similarity index 100% rename from scripts/CYCLONE_BASILISK/lamec.json rename to scripts/Cyclone/Basilisk/lamec.json diff --git a/Web_App/2023-11-20/.gitkeep b/scripts/Cyclone/Horovod/.gitkeep similarity index 100% rename from Web_App/2023-11-20/.gitkeep rename to scripts/Cyclone/Horovod/.gitkeep diff --git a/scripts/CYCLONE_Horovod/_script.sh b/scripts/Cyclone/Horovod/_script.sh similarity index 100% rename from scripts/CYCLONE_Horovod/_script.sh rename to scripts/Cyclone/Horovod/_script.sh diff --git a/scripts/CYCLONE_Horovod/lamec.json b/scripts/Cyclone/Horovod/lamec.json similarity index 100% rename from scripts/CYCLONE_Horovod/lamec.json rename to scripts/Cyclone/Horovod/lamec.json diff --git a/scripts/Cyclone/sysinfo.json b/scripts/Cyclone/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..ace36e58f286c61a40a8c7a1e84e137be64695de --- /dev/null +++ b/scripts/Cyclone/sysinfo.json @@ -0,0 +1,25 @@ +{ + "partition": { + "milan": { + "nodes": 34 + }, + "skylake": { + "nodes": 3 + }, + "nehalem": { + "nodes": 3 + }, + "cpu": { + "nodes": 13 + }, + "p100": { + "nodes": 8 + }, + "a100": { + "nodes": 6 + }, + "gpu": { + "nodes": 16 + } + } +} diff --git a/scripts/DEEP_DeepSpeed/DEEP_DeepSpeed_script.sh b/scripts/DEEP/DeepSpeed/DEEP_DeepSpeed_script.sh similarity index 100% rename from scripts/DEEP_DeepSpeed/DEEP_DeepSpeed_script.sh rename to scripts/DEEP/DeepSpeed/DEEP_DeepSpeed_script.sh diff --git a/scripts/DEEP_DeepSpeed/lamec.json b/scripts/DEEP/DeepSpeed/lamec.json similarity index 100% rename from scripts/DEEP_DeepSpeed/lamec.json rename to scripts/DEEP/DeepSpeed/lamec.json diff --git a/scripts/DEEP_HeAT/DEEP_HeAT_script.sh b/scripts/DEEP/HeAT/DEEP_HeAT_script.sh similarity index 100% rename from scripts/DEEP_HeAT/DEEP_HeAT_script.sh rename to scripts/DEEP/HeAT/DEEP_HeAT_script.sh diff --git a/scripts/DEEP_HeAT/lamec.json b/scripts/DEEP/HeAT/lamec.json similarity index 100% rename from scripts/DEEP_HeAT/lamec.json rename to scripts/DEEP/HeAT/lamec.json diff --git a/scripts/DEEP_Horovod/DEEP_Horovod_script.sh b/scripts/DEEP/Horovod/DEEP_Horovod_script.sh similarity index 100% rename from scripts/DEEP_Horovod/DEEP_Horovod_script.sh rename to scripts/DEEP/Horovod/DEEP_Horovod_script.sh diff --git a/scripts/DEEP_Horovod/lamec.json b/scripts/DEEP/Horovod/lamec.json similarity index 100% rename from scripts/DEEP_Horovod/lamec.json rename to scripts/DEEP/Horovod/lamec.json diff --git a/scripts/DEEP_Pytorch-DDP/DEEP_Pytorch-DDP_script.sh b/scripts/DEEP/Pytorch-DDP/DEEP_Pytorch-DDP_script.sh similarity index 100% rename from scripts/DEEP_Pytorch-DDP/DEEP_Pytorch-DDP_script.sh rename to scripts/DEEP/Pytorch-DDP/DEEP_Pytorch-DDP_script.sh diff --git a/scripts/DEEP_Pytorch-DDP/lamec.json b/scripts/DEEP/Pytorch-DDP/lamec.json similarity index 100% rename from scripts/DEEP_Pytorch-DDP/lamec.json rename to scripts/DEEP/Pytorch-DDP/lamec.json diff --git a/scripts/DEEP/sysinfo.json b/scripts/DEEP/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..8add8e4dc3f3b11191276c03eda2b2d51472f608 --- /dev/null +++ b/scripts/DEEP/sysinfo.json @@ -0,0 +1,10 @@ +{ + "partition": { + "dp-esb": { + "nodes": 75 + }, + "dp-dam": { + "nodes": 16 + } + } +} diff --git a/scripts/JURECA_DeepSpeed/JURECA_DeepSpeed_script.sh b/scripts/JURECA/DeepSpeed/JURECA_DeepSpeed_script.sh similarity index 100% rename from scripts/JURECA_DeepSpeed/JURECA_DeepSpeed_script.sh rename to scripts/JURECA/DeepSpeed/JURECA_DeepSpeed_script.sh diff --git a/scripts/JURECA_DeepSpeed/lamec.json b/scripts/JURECA/DeepSpeed/lamec.json similarity index 100% rename from scripts/JURECA_DeepSpeed/lamec.json rename to scripts/JURECA/DeepSpeed/lamec.json diff --git a/scripts/JURECA_HeAT/JURECA_HeAT_script.sh b/scripts/JURECA/HeAT/JURECA_HeAT_script.sh similarity index 100% rename from scripts/JURECA_HeAT/JURECA_HeAT_script.sh rename to scripts/JURECA/HeAT/JURECA_HeAT_script.sh diff --git a/scripts/JURECA_HeAT/lamec.json b/scripts/JURECA/HeAT/lamec.json similarity index 100% rename from scripts/JURECA_HeAT/lamec.json rename to scripts/JURECA/HeAT/lamec.json diff --git a/scripts/JURECA_Horovod/JURECA_Horovod_script.sh b/scripts/JURECA/Horovod/JURECA_Horovod_script.sh similarity index 100% rename from scripts/JURECA_Horovod/JURECA_Horovod_script.sh rename to scripts/JURECA/Horovod/JURECA_Horovod_script.sh diff --git a/scripts/JURECA_Horovod/lamec.json b/scripts/JURECA/Horovod/lamec.json similarity index 100% rename from scripts/JURECA_Horovod/lamec.json rename to scripts/JURECA/Horovod/lamec.json diff --git a/scripts/JURECA_Pytorch-DDP/JURECA_Pytorch-DDP_script.sh b/scripts/JURECA/Pytorch-DDP/JURECA_Pytorch-DDP_script.sh similarity index 100% rename from scripts/JURECA_Pytorch-DDP/JURECA_Pytorch-DDP_script.sh rename to scripts/JURECA/Pytorch-DDP/JURECA_Pytorch-DDP_script.sh diff --git a/scripts/JURECA_Pytorch-DDP/lamec.json b/scripts/JURECA/Pytorch-DDP/lamec.json similarity index 100% rename from scripts/JURECA_Pytorch-DDP/lamec.json rename to scripts/JURECA/Pytorch-DDP/lamec.json diff --git a/scripts/JURECA/sysinfo.json b/scripts/JURECA/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..06b09934ada142002fb65c9a72b25d9e14884b00 --- /dev/null +++ b/scripts/JURECA/sysinfo.json @@ -0,0 +1,19 @@ +{ + "partition": { + "dc-cpu": { + "nodes": 128 + }, + "dc-cpu-bigmem": { + "nodes": 48 + }, + "dc-cpu-devel": { + "nodes": 4 + }, + "dc-gpu": { + "nodes": 24 + }, + "dc-gpu-devel": { + "nodes": 4 + } + } +} diff --git a/scripts/JUWELS_DeepSpeed/JUWELS_DeepSpeed_script.sh b/scripts/JUWELS/DeepSpeed/JUWELS_DeepSpeed_script.sh similarity index 100% rename from scripts/JUWELS_DeepSpeed/JUWELS_DeepSpeed_script.sh rename to scripts/JUWELS/DeepSpeed/JUWELS_DeepSpeed_script.sh diff --git a/scripts/JUWELS_DeepSpeed/lamec.json b/scripts/JUWELS/DeepSpeed/lamec.json similarity index 100% rename from scripts/JUWELS_DeepSpeed/lamec.json rename to scripts/JUWELS/DeepSpeed/lamec.json diff --git a/scripts/JUWELS_HeAT/JUWELS_HeAT_script.sh b/scripts/JUWELS/HeAT/JUWELS_HeAT_script.sh similarity index 100% rename from scripts/JUWELS_HeAT/JUWELS_HeAT_script.sh rename to scripts/JUWELS/HeAT/JUWELS_HeAT_script.sh diff --git a/scripts/JUWELS_HeAT/lamec.json b/scripts/JUWELS/HeAT/lamec.json similarity index 100% rename from scripts/JUWELS_HeAT/lamec.json rename to scripts/JUWELS/HeAT/lamec.json diff --git a/scripts/JUWELS_Horovod/JUWELS_Horovod_script.sh b/scripts/JUWELS/Horovod/JUWELS_Horovod_script.sh similarity index 100% rename from scripts/JUWELS_Horovod/JUWELS_Horovod_script.sh rename to scripts/JUWELS/Horovod/JUWELS_Horovod_script.sh diff --git a/scripts/JUWELS_Horovod/lamec.json b/scripts/JUWELS/Horovod/lamec.json similarity index 100% rename from scripts/JUWELS_Horovod/lamec.json rename to scripts/JUWELS/Horovod/lamec.json diff --git a/scripts/JUWELS_Pytorch-DDP/JUWELS_Pytorch-DDP_script.sh b/scripts/JUWELS/Pytorch-DDP/JUWELS_Pytorch-DDP_script.sh similarity index 100% rename from scripts/JUWELS_Pytorch-DDP/JUWELS_Pytorch-DDP_script.sh rename to scripts/JUWELS/Pytorch-DDP/JUWELS_Pytorch-DDP_script.sh diff --git a/scripts/JUWELS_Pytorch-DDP/lamec.json b/scripts/JUWELS/Pytorch-DDP/lamec.json similarity index 100% rename from scripts/JUWELS_Pytorch-DDP/lamec.json rename to scripts/JUWELS/Pytorch-DDP/lamec.json diff --git a/scripts/JUWELS/sysinfo.json b/scripts/JUWELS/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..dd81dcb3fd271eb3048b5b0e0fe7ae72a9d776c1 --- /dev/null +++ b/scripts/JUWELS/sysinfo.json @@ -0,0 +1,25 @@ +{ + "partition": { + "batch": { + "nodes": 1024 + }, + "mem192": { + "nodes": 64 + }, + "devel": { + "nodes": 8 + }, + "gpus": { + "nodes": 46 + }, + "develgpus": { + "nodes": 2 + }, + "booster": { + "nodes": 384 + }, + "develbooster": { + "nodes": 4 + } + } +} diff --git a/scripts/LUMI_HeAT/LUMI_HeAT_script.sh b/scripts/LUMI/HeAT/LUMI_HeAT_script.sh similarity index 100% rename from scripts/LUMI_HeAT/LUMI_HeAT_script.sh rename to scripts/LUMI/HeAT/LUMI_HeAT_script.sh diff --git a/scripts/LUMI_HeAT/lamec.json b/scripts/LUMI/HeAT/lamec.json similarity index 100% rename from scripts/LUMI_HeAT/lamec.json rename to scripts/LUMI/HeAT/lamec.json diff --git a/scripts/lumi_ddp/README.md b/scripts/LUMI/Pytorch-DDP/README.md similarity index 100% rename from scripts/lumi_ddp/README.md rename to scripts/LUMI/Pytorch-DDP/README.md diff --git a/scripts/lumi_ddp/container_build.sh b/scripts/LUMI/Pytorch-DDP/container_build.sh similarity index 100% rename from scripts/lumi_ddp/container_build.sh rename to scripts/LUMI/Pytorch-DDP/container_build.sh diff --git a/scripts/lumi_ddp/container_env.sh b/scripts/LUMI/Pytorch-DDP/container_env.sh similarity index 100% rename from scripts/lumi_ddp/container_env.sh rename to scripts/LUMI/Pytorch-DDP/container_env.sh diff --git a/scripts/lumi_ddp/container_startscript.sh b/scripts/LUMI/Pytorch-DDP/container_startscript.sh similarity index 100% rename from scripts/lumi_ddp/container_startscript.sh rename to scripts/LUMI/Pytorch-DDP/container_startscript.sh diff --git a/scripts/lumi_ddp/env_build.sh b/scripts/LUMI/Pytorch-DDP/env_build.sh similarity index 100% rename from scripts/lumi_ddp/env_build.sh rename to scripts/LUMI/Pytorch-DDP/env_build.sh diff --git a/scripts/lumi_ddp/env_startscript.sh b/scripts/LUMI/Pytorch-DDP/env_startscript.sh similarity index 100% rename from scripts/lumi_ddp/env_startscript.sh rename to scripts/LUMI/Pytorch-DDP/env_startscript.sh diff --git a/scripts/lumi_ddp/lamec.json b/scripts/LUMI/Pytorch-DDP/lamec.json similarity index 100% rename from scripts/lumi_ddp/lamec.json rename to scripts/LUMI/Pytorch-DDP/lamec.json diff --git a/scripts/lumi_ddp/reqs.txt b/scripts/LUMI/Pytorch-DDP/reqs.txt similarity index 100% rename from scripts/lumi_ddp/reqs.txt rename to scripts/LUMI/Pytorch-DDP/reqs.txt diff --git a/scripts/LUMI/sysinfo.json b/scripts/LUMI/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..7d5bd887c0270530c6a6d0404b12751e423df670 --- /dev/null +++ b/scripts/LUMI/sysinfo.json @@ -0,0 +1,25 @@ +{ + "partition": { + "standard-g": { + "nodes": 1024 + }, + "standard": { + "nodes": 512 + }, + "dev-g": { + "nodes": 32 + }, + "debug": { + "nodes": 4 + }, + "small-g": { + "nodes": 4 + }, + "small": { + "nodes": 4 + }, + "largemem": { + "nodes": 1 + } + } +} diff --git a/scripts/VEGA_Basilisk/_script.sh b/scripts/VEGA/Basilisk/_script.sh similarity index 100% rename from scripts/VEGA_Basilisk/_script.sh rename to scripts/VEGA/Basilisk/_script.sh diff --git a/scripts/VEGA_Basilisk/lamec.json b/scripts/VEGA/Basilisk/lamec.json similarity index 100% rename from scripts/VEGA_Basilisk/lamec.json rename to scripts/VEGA/Basilisk/lamec.json diff --git a/scripts/VEGA/sysinfo.json b/scripts/VEGA/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..522877bc0f893abc068dca415d7ff382a57f650d --- /dev/null +++ b/scripts/VEGA/sysinfo.json @@ -0,0 +1,19 @@ +{ + "partition": { + "dev": { + "nodes": 8 + }, + "cpu": { + "nodes": 960 + }, + "longcpu": { + "nodes": 6 + }, + "gpu": { + "nodes": 60 + }, + "largemem": { + "nodes": 192 + } + } +} diff --git a/scripts/info.json b/scripts/info.json new file mode 100644 index 0000000000000000000000000000000000000000..245322bf71c3848fd8a941ff99f0ac14d5bd257a --- /dev/null +++ b/scripts/info.json @@ -0,0 +1,50 @@ +{ + "defs": { + "system": { + "type": "option", + "desc": "Select the computing system on which you want to submit your job." + }, + "software": { + "type": "option", + "desc": "Select the software your job depends on.", + "depends_on": ["system"] + }, + "partition": { + "type": "option", + "desc": "Select the partition for your job.", + "depends_on": ["system"] + }, + "nodes": { + "type": "range", + "desc": "Select the number of nodes.", + "depends_on": ["system", "partition"], + "default": 1 + }, + "account": { + "type": "string", + "desc": "Specify the account for your job.", + "default": "Account" + }, + "executable": { + "type": "string", + "desc": "Specify an executable for your job.", + "default": "app" + } + }, + "docs": { + "system": { + "JURECA": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", + "DEEP": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", + "JUWELS": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", + "LUMI": "https://docs.lumi-supercomputer.eu/software/", + "VEGA": "https://doc.vega.izum.si", + "Cyclone": "https://hpcf.cyi.ac.cy/documentation/" + }, + "software": { + "Pytorch-DDP": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", + "Horovod": "https://horovod.readthedocs.io/en/stable/", + "DeepSpeed": "https://deepspeed.readthedocs.io/en/latest/", + "HeAT": "https://heat.readthedocs.io/en/stable/" + } + } +} diff --git a/scripts/rudens_ddp/.gitkeep b/scripts/rudens_ddp/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/scripts/vsc_ddp/.gitkeep b/scripts/vsc_ddp/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/status.php b/status.php new file mode 100644 index 0000000000000000000000000000000000000000..19a5637393f61e558db9e14584f9b906639dd922 --- /dev/null +++ b/status.php @@ -0,0 +1,25 @@ +<?php +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $raw_data = file_get_contents('php://input'); + $json_data = json_decode($raw_data, true); + $file = fopen('/data/status.json', 'r'); + $data = json_decode(fread($file, filesize('/data/status.json')), true); + if (array_key_exists($json_data['system'], $data)) { + if (array_key_exists($json_data['software'], + $data[$json_data['system']])) { + $data[$json_data['system']][$json_data['software']]['passed'] + = $json_data['passed']; + } + } + fclose($file); + + $file = fopen('/data/status.json', 'w'); + fwrite($file, json_encode($data, JSON_PRETTY_PRINT)); + fclose($file); +} else { + include 'render.php'; + $active = 'status'; + $content = loadFragment('html/status.html'); + include 'base.php'; +} +?> diff --git a/update.py b/update.py new file mode 100644 index 0000000000000000000000000000000000000000..ef338d9d3396af7bc28f308854fa968571977588 --- /dev/null +++ b/update.py @@ -0,0 +1,182 @@ +import lamec +import sys +import os +import json + +def get_defs(): + with open(f'{lamec.scriptpath}/info.json', 'r') as f: + info = json.load(f) + return info['defs'] + +def get_docs(): + with open(f'{lamec.scriptpath}/info.json', 'r') as f: + info = json.load(f) + return info['docs'] + +def get_system(vardef): + builder = VarBuilder('system', vardef['type'], vardef['desc']) + for system in os.scandir(lamec.scriptpath): + if system.name.startswith('.') or os.path.isdir(system) == False: + continue + builder.add(system.name) + builder.values.sort() + return builder.build() + +def get_software(vardef): + builder = VarBuilder('software', + vardef['type'], + vardef['desc'], + depends_on=vardef['depends_on']) + software = [] + for system in os.scandir(lamec.scriptpath): + if system.name.startswith('.') or os.path.isdir(system) == False: + continue + value = [] + for software in os.scandir(f'{lamec.scriptpath}/{system.name}'): + if software.name.startswith('.') or os.path.isdir(software) == False: + continue + value.append(software.name) + builder.add(value, resolve_on=[system.name]) + return builder.build() + +def get_partition(vardef): + builder = VarBuilder('partition', + vardef['type'], + vardef['desc'], + depends_on=vardef['depends_on']) + for system in os.scandir(lamec.scriptpath): + if system.name.startswith('.') or os.path.isdir(system) == False: + continue + value = [] + sysinfo = get_sysinfo(system.name) + for partition in sysinfo['partition']: + value.append(partition) + builder.add(value, resolve_on=[system.name]) + return builder.build() + +def get_nodes(vardef): + builder = VarBuilder('nodes', + vardef['type'], + vardef['desc'], + depends_on=vardef['depends_on']) + for system in os.scandir(lamec.scriptpath): + if system.name.startswith('.') or os.path.isdir(system) == False: + continue + sysinfo = get_sysinfo(system.name) + for partition in sysinfo['partition']: + value = [1, sysinfo['partition'][partition]['nodes']] + builder.add(value, resolve_on=[system.name, partition]) + return builder.build() + +def get_sysinfo(system): + with open(f'{lamec.scriptpath}/{system}/sysinfo.json', 'r') as f: + sysinfo = json.load(f) + return sysinfo + + +class VarBuilder: + def __init__(self, name, typename, desc, default=None, depends_on=[]): + self.name = name + self.typename = typename + self.desc = desc + self.default = default + self.depends_on = depends_on + self.values = [] + + def add(self, value, resolve_on=[]): + if len(resolve_on) != 0: + self.values.append({'key': resolve_on, 'value': value}) + else: + self.values.append(value) + + def build(self): + d = dict() + d['name'] = self.name + d['desc'] = self.desc + if self.typename == 'option' or self.typename == 'range': + if self.typename == 'option': + d['type'] = 'string' + else: + d['type'] = 'number' + d['restriction'] = dict() + d['restriction']['type'] = self.typename + d['restriction']['value'] = dict() + if len(self.depends_on): + d['restriction']['value']['depends_on'] = dict() + d['restriction']['value']['depends_on']['fields'] = self.depends_on + d['restriction']['value']['depends_on']['resolution'] = [] + for value in self.values: + d['restriction']['value']['depends_on']['resolution'].append(value) + else: + d['restriction']['value'] = self.values + else: + d['type'] = self.typename + if self.default: + d['default'] = self.default + return d + +def get_free_variable(name, defs): + vardef = defs[name] + default = None + if 'default' in vardef: + default = vardef['default'] + builder = VarBuilder(name, + vardef['type'], + vardef['desc'], + default) + return builder.build() + +def set_scope(fields): + scope = dict() + for system in os.scandir(lamec.scriptpath): + if system.name.startswith('.') or os.path.isdir(system) == False: + continue + for software in os.scandir(f'{lamec.scriptpath}/{system.name}'): + if software.name.startswith('.') or os.path.isdir(software) == False: + continue + template = lamec.get_template(system.name, software.name) + if template: + variables = lamec.get_placeholders(template) + for var in variables: + if var not in scope: + scope[var] = [] + scope[var].append([system.name, software.name]) + for key in scope: + for field in fields: + if field['name'] == key and 'restriction' not in field: + if 'scope' not in field: + field['scope'] = [] + field['scope'].append({'fields': ['system', 'software'], + 'values': scope[key]}) + ''' + for field in fields: + if field['name'] not in ['system', 'software'] and 'scope' not in field: + field['scope'] = [] + ''' + +def update_all(): + fields = [] + with open(f'{lamec.scriptpath}/info.json', 'r') as f: + info = json.load(f) + defs = info['defs'] + dependent_variables = ['system', 'software', 'partition', 'nodes'] + callbacks = { + 'system': get_system, + 'software': get_software, + 'partition': get_partition, + 'nodes': get_nodes} + for var in dependent_variables: + fields.append(callbacks[var](defs[var])) + for var in defs: + if var not in dependent_variables: + fields.append(get_free_variable(var, defs)) + form_schema = {'fields': fields, 'documentation': info['docs']} + set_scope(fields) + with open('data/form-schema.json', 'w') as out: + json.dump(form_schema, out, indent=4) + +def main(): + update_all() + +if __name__ == '__main__': + main()