- Справочник API
- HTML и CSS для AnyLogic Cloud
- Примеры
- «Прогон» эксперимента без анимации (простой)
- Запрос результатов завершенного «прогона»
- Прогон эксперимента с опросом о ходе выполнения
- Запуск нестандартного потока операций
- Запуск эксперимента варьирования параметров
- Запуск Монте-Карло 1-го порядка
- Простой эксперимент с анимацией (простой)
- Запуск анимации с кнопками паузы и возобновления и опросом статуса
- Прогон анимации с внешним управлением параметрами модели
- Получение информации во время прогона анимированной модели
Обновлено 09.12.2024
JavaScript API используется для создания пользовательских веб-интерфейсов для моделей AnyLogic Cloud с анимацией или без нее.
Чтобы начать использовать API
-
Подключите библиотеку cloud_client, добавив тег <script> в заголовок вашей веб-страницы:
<script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script>
Для пользователей Private Cloud адрес выглядит следующим образом:<script src="http(s)://<имя хоста Private Cloud>/assets/js-client-8.5.0/cloud-client.js"></script>
- Получите ключ API в пользовательском интерфейсе AnyLogic Cloud.
-
Создайте новый экземпляр объекта CloudClient:
cloudClient = CloudClient.create( <apiKey> ), если вы используете общедоступную версию AnyLogic Cloud, или
cloudClient = CloudClient.create( <apiKey>, <URL экземпляра Cloud> ); - Используйте API для работы с моделями AnyLogic Cloud.
Если вы используете ключ API в коде JavaScript своей пользовательской веб-страницы (общедоступной или открытой для конечного пользователя или клиента), он будет доступен всем, кто имеет доступ к этой странице, поскольку все могут просматривать код JavaScript в консоли браузера. Имея доступ к коду API, можно использовать AnyLogic Cloud API, используя учетную запись, в которой хранится ключ.
Чтобы защитить свою учетную запись:
-
Создавайте отдельные учетные записи Cloud для потенциальных пользователей.
Чтобы использовать API, пользователи общедоступного Cloud должны иметь подписку. - Создавайте отдельные ключи API для этих учетных записей.
- В демонстрационных целях используйте ключ API для демо-аккаунта.
- Предоставляйте доступ к демонстрационной модели пользователям, имеющим учетную запись разработчика и учетную запись пользователя.
- AnyLogic Cloud JavaScript API полностью асинхронный и широко использует технологию промисов.
- Настройки вашего компилятора IDE должны разрешать ECMAScript 6.
- Отправляя API аргументы и значения переменных (например, имена моделей и необработанный JSON), убедитесь, что экранировали специальные символы с помощью знака обратной косой черты (\).
Класс CloudClient отвечает за аутентификацию и взаимодействие с AnyLogic Cloud.
Как правило, в вашем коде JavaScript может быть только один объект класса CloudClient.
Функция | Описание |
---|---|
create(apiKey, host) |
Статическая функция, которая создает клиента API с заданным ключом API и, при необходимости, именем хоста. Если хост опущен, подразумевается имя хоста общедоступного Cloud https://cloud.anylogic.com. |
getModels() | Возвращает промис с доступными моделями в виде массива объектов Model. |
getModelById(id) | Возвращает промис с объектом Model с заданным идентификатором id. |
getModelByName(name) | Возвращает промис с объектом Model с заданным именем name. |
getModelVersionById(model, versionId) | Возвращает промис с объектом Version заданного объекта Model с заданным идентификатором versionId. |
getModelVersionByNumber(model, versionNumber) | Возвращает промис с объектом Version заданного объекта Model с заданным номером versionNumber (нумерация версий начинается с 1). |
getLatestModelVersion(<model or name>) | Возвращает промис с объектом Version, соответствующим последней версии данной модели (может быть объектом Model или именем модели). |
createDefaultInputs(version) | Создает и возвращает объект Inputs для объекта Version данной модели со значениями входных данных по умолчанию. |
createInputsFromExperiment(version, experimentName) | Создает и возвращает промис с объектом Inputs для объекта Version данной модели, скопированного из эксперимента с данным именем. |
createSimulation(inputs) | Создает и возвращает объект ModelRun типа SIMULATION с заданным значением объекта Inputs (модель и версия идентифицируются по Inputs). |
createParameterVariation(inputs) | Создает и возвращает объект ModelRun типа PARAMETER_VARIATION с заданным значением объекта Inputs (модель и версия идентифицируются по Inputs). |
createMonteCarloFirstOrder(inputs) | Создает и возвращает объект ModelRun типа MONTE_CARLO с заданным значением объекта Inputs (модель и версия идентифицируются по Inputs). |
startAnimation(inputs, divId) | Запускает анимацию модели с заданным значением объекта Inputs (который полностью идентифицируют модель и версию модели) и встраивает анимацию в HTML-элемент с заданным идентификатором. Создает и возвращает промис с соответствующим объектом Animation. |
Объект класса Inputs создается при подготовке запуска модели любого типа путем вызова функций CloudClient: createDefaultInputs() или createInputsFromExperiment(). Этот объект содержит всю информацию о модели, версии модели и входных данных.
Функция | Описание |
---|---|
getInput(name) | Возвращает значение элемента входных данных с заданным именем. Возможные типы см. в разделе Преобразование данных. |
setInput(name, value) | Устанавливает значение элемента входных данных с заданным именем. |
setRangeInput(name, min, max, step) | Устанавливает диапазон для элемента входных данных с заданным именем (в эксперименте с варьированием параметров). |
setNumberOfReplications(num) | Устанавливает число репликаций для эксперимента Монте-Карло первого порядка. Значение по умолчанию — 3. |
Входные данные типа распределения (для экспериментов Монте-Карло второго порядка) появятся в будущих версиях AnyLogic Cloud API.
Объект этого класса возвращается после вызова функций getOutputs() или getOutputsAndRunIfAbsent() объекта ModelRun, созданного для эксперимента с одним «прогоном».
Функция | Описание |
---|---|
names() | Возвращает массив со всеми именами элементов выходных данных. |
findNameIncluding(namePart) | Ищет имя элемента выходных данных, содержащее namePart в качестве подстроки, и возвращает его. Если такого имени нет или найдено более одного имени, выдает ошибку. Эта функция нужна, так как полные имена элементов выходных данных могут быть составными: см. Объекты выходных данных. |
value(name) | Возвращает значение элемента выходных данных с заданным именем. Тип значения зависит от типа элемента выходных данных: см. Преобразование данных. |
getRawOutputs() |
Возвращает массив всех элементов выходных данных. Каждый элемент имеет следующие поля: name, type, units, value. Возможные значения полей type и units см. в разделах Типы выходных данных и Единицы измерения соответственно. Поле значения содержит объект, созданный, как описано в разделе Преобразование данных.
|
Объект этого класса возвращается после вызова функций getOutputs() или getOutputsAndRunIfAbsent() объекта ModelRun, созданного для эксперимента варьирования параметров или другого эксперимента с несколькими «прогонами». Это упрощает навигацию по сложной структуре выходных данных.
Функция | Описание |
---|---|
getInputNames() | Возвращает массив имен элементов входных данных, различающихся для разных прогонов. |
getOutputNames() | Возвращает массив имен запрошенных элементов выходных данных. |
getValuesOfInput(name) | Возвращает массив значений элементов входных данных с заданным именем для всех прогонов в некоторой фиксированной последовательности. Вы можете получить значения только варьирующихся элементов входных данных. Фиксированные входные данные не хранятся в классе MultiRunOutputs. |
getValuesOfOutput(name) | Возвращает массив значений элементов выходных данных с заданным именем для всех прогонов в некоторой фиксированной последовательности. Эту функцию можно использовать вместе с getValuesOfInput(). |
getRawData() |
Возвращает таблицу (двумерный массив) со значениями всех переменных входных данных и всех выходных данных со строкой заголовка. Например, ниже приведены необработанные данные эксперимента с варьированием параметров с одним переменным параметром Mean service time и одним скалярным выходным значением Utilization|Server utilization:
|
Класс ModelRun отвечает за обмен информацией во время прогона модели и контролирует этот прогон (без анимации, в Cloud). По сути, это внешний интерфейс внутренних процессов прогона эксперимента.
Объекты класса ModelRun создаются и возвращаются путем вызова функций createSimulation(), createParameterVariation() или createMonteCarloFirstOrder() класса CloudClient. Объект ModelRun содержит всю информацию о модели, версии, входных данных и типе эксперимента.
Функция | Описание |
---|---|
run() | Запрашивает запуск эксперимента. О фактическом выполнении эксперимента говорит наличие выходных данных. Функция возвращает промис с тем же объектом ModelRun после завершения HTTP-запроса; она не ожидает завершения эксперимента или появления выходных данных и не отсылает дополнительных запросов. |
stop() | Запрашивает остановку выполнения модели. Возвращает промис с тем же объектом ModelRun после завершения HTTP-запроса. |
waitForCompletion(pollingPeriod) | Ожидает завершения эксперимента и возвращает промис с тем же объектом ModelRun. Параметр pollingPeriod является необязательным. Значение по умолчанию: 5000ms. |
getStatus() | Возвращает статус выполнения модели, который последний раз обновлялся с помощью опроса (не инициирует дополнительную связь с сервером). Возможные значения такие же, как описано в разделе Статус прогона эксперимента. |
getProgress() | Возвращает промис с полностью обработанным полем message объекта Experiment Run State. Чтобы узнать о ходе выполнения эксперимента, используйте нотацию getProgress().then( progress => progress.total). |
getOutputs(requiredOutputNames) |
Если «прогон» уже завершен, возвращает промис с выходными данными «прогона» (либо объект SingleRunOutputs, либо объект MultiRunOutputs), в противном случае выдает ошибку 404. requiredOutputNames — это массив возвращаемых выходных имен. Если requiredOutputNames опущен, поведение экспериментов с одним и несколькими прогонами отличается: для одного «прогона» возвращаются все выходные данные, для многократного «прогона» возвращаются только выходные данные скалярных типов. |
getOutputsAndRunIfAbsent(requiredOutputNames, pollingPeriod) | Если прогон уже завершен, возвращает промис с выходными данными «прогона» (либо объект SingleRunOutputs, либо объект MultiRunOutputs), в противном случае запрашивает запуск эксперимента, ожидает завершения, делая опрос, а затем возвращает промис с выходными данными. requiredOutputNames имеет такое же значение, как и для функции getOutputs(). Параметр pollingPeriod необязателен. Значение по умолчанию: 5000ms. |
Класс Animation отвечает за обмен информацией во время прогона эксперимента с анимацией и контролирует этот прогон. Объект класса Animation создается и возвращается путем вызова функции startAnimation() класса CloudClient.
Функция | Описание |
---|---|
stop() | Запрашивает остановку выполнения модели. Ничего не возвращает. |
pause() | Запрашивает приостановку выполнения модели. Возвращает промис с тем же объектом Animation. |
resume() | Запрашивает возобновление (приостановленного) выполнения модели. Возвращает промис с тем же объектом Animation. |
setSpeed(speed) | Запрашивает установку скорости выполнения модели на заданное значение (единицы модельного времени за реальную секунду). Возвращает промис с тем же объектом Animation. |
setVirtualTime() | Запрашивает переключение в режим виртуального времени (максимальная скорость). Возвращает промис с тем же объектом Animation. |
navigateTo(viewArea) | Запрашивает переход к области просмотра с заданным именем. Возвращает промис с тем же объектом Animation. |
setPresentable(pathToPresentable) | Запрашивает переход к определенному агенту. Путь должен начинаться с experiment.root, за которым следует путь Java к агенту (если это не root). Возвращает промис с тем же объектом Animation. |
setValue(pathToField, value) | Запрашивает установку значения данного объекта в модели (например, параметра или переменной). Путь к объекту должен выглядеть так: experiment.root.agent1.myParameter. Возвращает промис с тем же объектом Animation. |
getValue(pathToField) | Запрашивает значение данного объекта в модели и возвращает промис с этим значением. Путь к объекту должен выглядеть так: experiment.root.agent1.myParameter. Возвращаемое значение будет в формате JSON: см. раздел Преобразование данных, чтобы узнать, как объекты Java сопоставляются с объектами JSON. |
getState() |
Запрашивает статус выполнения анимации модели и возвращает промис с этим значением. Не путайте статус анимации модели со статусом прогона модели без анимации, возвращаемого функцией ModelRun.getStatus(). Возвращает одно из следующих значений: "IDLE" (модель не выполняется, ничего не происходит) |
callFunction(pathToFunction, args) |
Запрос на вызов функции в модели, возможно с аргументами. Возвращает промис с тем значением, которое возвращает сама функция. Путь к функции должен выглядеть так: experiment.root.agent1.myFunction. args — это массив JavaScript с объектами аргументов функции. См. раздел Преобразование данных, чтобы узнать, как объекты Java сопоставляются с объектами JSON. |
waitForCompletion() |
Ожидает завершения анимации эксперимента и возвращает промис с тем же объектом Animation.
Даже если прогон эксперимента закончился (достигнуто время остановки), он не будет считаться завершенным до тех пор, пока пользователь или не щелкнет по кнопке Стоп, или пока не будет вызвана функция stop(), или сервер не завершит эксперимент из-за ошибки.
|
Если вы хотите встроить анимацию модели на свою веб-страницу, убедитесь, что в CSS и HTML нет пересечения по ID между элементами, принадлежащими вашей странице, и встроенной анимацией AnyLogic.
«Прогон» эксперимента без анимации (простой)
-
В этом примере мы запускаем эксперимент без анимации. Сначала находим модель и ее последнюю версию. Далее указываем входные параметры модели. Если эксперимент с такими входными данными уже завершен (и выходные данные находятся в Cloud), выходные данные просто передаются в веб-интерфейс. В противном случае эксперимент запускается в быстром режиме без анимации. Выходные данные генерируются и отправляются во внешний интерфейс.
Для этого используйте функцию ModelRun.getOutputsAndRunIfAbsent().
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Run simulation. Minimalistic</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runSimulation()">Run simulation</button> <div id="info">The simulation results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let info; let inputs; window.onload = () => { runButton = document.getElementById("run-button"); info = document.getElementById("info"); }; function runSimulation() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Service System Demo" ) .then( version => { inputs = cloudClient.createDefaultInputs( version ); inputs.setInput( "Server capacity", 8 ); let simulation = cloudClient.createSimulation(inputs); info.innerHTML = "Getting outputs, running simulation if absent..."; return simulation.getOutputsAndRunIfAbsent(); }) .then( outputs => { let html = "For Server Capacity = " + inputs.getInput( "Server capacity" ) + ":<br>"; html += "Mean queue size = " + outputs.value( "Mean queue size|Mean queue size" ) + "<br>"; html += "Server utilization = " + outputs.value( "Utilization|Server utilization" ) + "<br>"; info.innerHTML = html; }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error( error ); }) .finally( () => { runButton.disabled = false; }); }
-
Попробуйте: Запустить эксперимент, простой
API JavaScript-клиент AnyLogic Cloud находится в HTML, как описано ранее в руководстве по установке. Также есть кнопка и элемент div для отображения результатов эксперимента.
По мере загрузки веб-страницы и скриптов создается объект CloudClient с заданным ключом API. Вторым опциональным параметром статической функции CloudClient.create() является URL-адрес Cloud. Здесь он опущен, поэтому предполагается общедоступная версия AnyLogic Cloud.
Когда пользователь щелкает по кнопке Запустить, вызывается функция runSimulation(). Эта функция отключает кнопку и инициирует цепочку взаимодействия клиент-сервер с помощью промиса JavaScript:
- Сервер находит последнюю версию модели Service System Demo.
- Когда (и если) такая модель и версия найдены (первая функция then), мы создаем объект Inputs с входными данными по умолчанию. В этих входных данных мы меняем значение параметра Server capacity на 8. Далее запрашиваем CloudClient создать объект simulation с входными данными. Это полностью взаимодействие с внешним интерфейсом, коммуникации с сервером нет. Этот блок кода завершается вызовом функции getOutputsAndRunIfAbsent(), которая проверяет статус эксперимента: если этот эксперимент завершен, функция возвращает выходные данные. Если эксперимент еще не запускался, эта функция запускает его и ожидает получения выходных данных. Объект SingleRunOutputs возвращается промисом.
- Когда выходные данные получены, с помощью API объектов SingleRunOutputs и Inputs отображаются некоторые выходные значения и соответствующие входные данные. Если во время всех этих действий не возникает ошибок, переходим сразу к блоку finally, где снова активируем кнопку Запустить.
-
Если на каком-либо шаге возникает ошибка, вызывается блок catch. Отображается сообщение об ошибке и оно копируется в консоль. Затем выполняется блок finally.
Чтобы получить значение конкретных выходных данных, нужно указать имя этих данных именно так, как оно обозначено при загрузке модели в Cloud (подробнее см. в разделе об объекте Output. Регистр не учитывается: можно использовать и нижний, и верхний регистры.
Функция runSimulation() завершается немедленно, а фрагменты кода в блоках then, catch и finally вызываются позже, когда происходят соответствующие события.
Запрос результатов завершенного «прогона»
-
Как вы знаете, AnyLogic Cloud хранит пары входных/выходных данных для всех когда-либо завершенных прогонов экспериментов. В этом примере мы покажем вам, как запрашивать выходные данные завершенного прогона модели (который идентифицируется по входным данным). Если результаты существуют, они будут отображены, в противном случае выводится соответствующее сообщение, а не запускается эксперимент, как было сделано в предыдущем примере.
Здесь используется ключевая функция ModelRun.getOutputs().
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Query outputs of a completed run</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> Server capacity: <span id="parameter-value">5</span> <input id="parameter-range" type="range" min="2" max="10" step="1" value="5" onchange="changeValueText()"> <button id="query-button" onclick="queryOutputs()">Query outputs</button> <div id="info">The simulation results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let parameterValue; let parameterRange; let queryButton; let info; window.onload = () => { parameterValue = document.getElementById("parameter-value"); parameterRange = document.getElementById("parameter-range"); queryButton = document.getElementById("query-button"); info = document.getElementById("info"); }; function queryOutputs() { parameterRange.disabled = true; queryButton.disabled = true; cloudClient.getModelByName("Service System Demo") .then( model => cloudClient.getLatestModelVersion(model) ) .then( version => { let inputs = cloudClient.createDefaultInputs(version); inputs.setInput( "Server capacity", parameterRange.value); let simulation = cloudClient.createSimulation(inputs); info.innerHTML = "Getting outputs..."; return simulation.getOutputs(); }) .then( outputs => { let html = "Mean queue size = " + outputs.value(outputs.findNameIncluding("Mean Queue Size")) + "<br>"; html += "Server utilization = " + outputs.value(outputs.findNameIncluding("Server utilization")) + "<br>"; info.innerHTML = html; }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error(error); }) .finally( () => { parameterRange.disabled = false; queryButton.disabled = false; }); } function changeValueText() { parameterValue.innerText = parameterRange.value; }
-
Попробуйте: Запрос результатов завершенного «прогона»
В HTML-коде есть input элемент типа диапазон, который используется для установки значения мощности сервера. После создания объектов inputs и simulation, вызывается функция simulation.getOutputs(). Если выходные данные существуют, они возвращаются промисом, и мы переходим к следующему блоку then. Если выходных данных нет, выпадает ошибка, и мы переходим к блоку catch и отображаем ошибку. Этот же блок catch выполняется, если возникает ошибка любого другого типа. Если вы хотите использовать конкретную функцию-обработчик (handler) в случае отсутствия результатов, вы можете модифицировать код следующим образом:
... return simulation.getOutputs() .catch( error => { if( error.status == 404 ) { //custom handler code console.error("Simulation results not found for these inputs"); } throw new Error("Outputs not found for Server Capacity = " + parameterRange.value); }); ...
Прогон эксперимента с опросом о ходе выполнения
-
В случае если эксперимент запускается без анимации, целесообразно иметь какое-то визуальное отображение прогресса.
В этом примере мы используем функцию ModelRun.getProgress() для получения информации о ходе выполнения эксперимента. Существует также другой способ запуска эксперимента и получения результатов: последовательный вызов функций run(), waitForCompletion() и getOutputs().
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Simulation with Progress indication</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runSimulation()">Run simulation</button> <progress id="progress" value="0" max="100"></progress> <div id="info">The simulation results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let progress; let info; let simulation; window.onload = () => { runButton = document.getElementById( "run-button" ); progress = document.getElementById( "progress" ); info = document.getElementById( "info" ); }; function runSimulation() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Service System Demo" ) .then( version => { let inputs = cloudClient.createDefaultInputs( version ); inputs.setInput( "Server capacity", 21 ); inputs.setInput( "{STOP_TIME}", 10000000 ); simulation = cloudClient.createSimulation(inputs); startPolling(); return simulation.run(); }) .then( simulation => simulation.waitForCompletion() ) .then( simulation => simulation.getOutputs() ) .then( outputs => { let html = "Mean queue size = " + outputs.value( "Mean queue size|Mean queue size" ) + "<br>"; html += "Server utilization = " + outputs.value( "Utilization|Server utilization" ) + "<br>"; info.innerHTML = html; }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error( error ); }) .finally( () => { stopPolling(); runButton.disabled = false; }); } let pollingInterval; function startPolling() { pollingInterval = setInterval( () => { simulation.getProgress() .then( progressinfo => { if( progressinfo ) { //can be undefined in the beginning progress.value = progressinfo.total; } }); }, 1000 ); } function stopPolling() { setTimeout( () => clearInterval( pollingInterval ), 2000 ); }
-
Попробуйте: Простой эксперимент с отображением хода выполнения
При стандартном создании входных данных мы увеличиваем значение системных входных данных {STOP_TIME}, чтобы увеличить продолжительность эксперимента. Таким образом мы сможем увидеть движение индикатора выполнения. Эти входные данные есть в каждой модели, загруженной в Cloud. Однако если прогон с таким же временем остановки и другими входными данными уже был выполнен, эксперимент не запустится, а выходные данные будут получены почти мгновенно. Таким образом, чтобы следить за ходом выполнения, попробуйте установить другие значения для входных данных.
Функция startPolling() вызывается прямо перед simulation.run() и инициируют повторяющийся вызов simulation.getProgress() с интервалом в одну секунду. Функция getProgress() возвращает промис с информацией о прогрессе. Для запуска простого эксперимента нас интересует только поле total. Для экспериментов с несколькими «прогонами» это поле содержит больше деталей.
Результатом может быть пустой объект, если мы делаем запрос слишком рано (пока «прогон» еще не создан на сервере), поэтому нужно убедиться в наличии результатов опроса. Функция stopPolling() вызывается после получения результатов эксперимента (или при возникновении ошибки). Она удаляет интервал в одну секунду, но ждет еще две секунды, чтобы убедиться, что получено окончательное значение прогресса.Вызов функции simulation.run() инициирует запуск эксперимента (только если запуск не был выполнен ранее) и возвращает промис с тем же объектом simulation. Функция не ждет завершения эксперимента. Чтобы дождаться завершения эксперимента, используется функция simulation.waitForCompletion(), которая также возвращает тот же объект. Только теперь мы можем запрашивать результаты эксперимента, вызывая функцию simulation.getOutputs(). Эта последовательность здесь исключительно для демонстрационных целей. Ее можно заменить одним вызовом simulation.getOutputsAndRunIfAbsent().
-
Запуск нестандартного потока операций
-
В этом примере показан нестандартный поток операций, в котором некоторые эксперименты выполняются параллельно, а некоторые — последовательно, на основе результатов других экспериментов. Этот сценарий может быть интересен тем, кто, например, планирует настроить алгоритм оптимизации в AnyLogic Cloud.
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Custom workflow</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runSimulations()">Run 2+1 simulations</button> <div id="info">The simulation results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let version; let runButton; let info; window.onload = () => { runButton = document.getElementById( "run-button" ); info = document.getElementById( "info" ); }; let sc1 = 4; let sc2 = 9; let sc3; function runSimulations() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Service System Demo" ) .then( v => { version = v; //create two inputs instances with different parameter values let inputs1 = cloudClient.createDefaultInputs( version ); let inputs2 = cloudClient.createDefaultInputs( version ); inputs1.setInput( "Server capacity", sc1 ); inputs2.setInput( "Server capacity", sc2 ); //create two simulation objects with different inputs let simulation1 = cloudClient.createSimulation( inputs1 ); let simulation2 = cloudClient.createSimulation( inputs2 ); info.innerHTML = "Running two parallel simulations...<br>"; //run the two simulations in parallel, wait for both results return Promise.all( [simulation1.getOutputsAndRunIfAbsent(), simulation2.getOutputsAndRunIfAbsent()] ); }) .then( outputarray => { //both outputs are here let su1 = outputarray[0].value( "Utilization|Server utilization" ); let su2 = outputarray[1].value( "Utilization|Server utilization" ); let html = "Two parallel simulations completed.<br>"; html += "With " + sc1 + " servers, Server utilization = " + su1 + "<br>"; html += "With " + sc2 + " servers, Server utilization = " + su2 + "<br>"; //based on the results, set up the inputs for the third simulation sc3 = (su1 + su2) > 0.4 ? sc2-1 : sc1+1; let inputs3 = cloudClient.createDefaultInputs( version ); inputs3.setInput( "Server capacity", sc3 ); let simulation3 = cloudClient.createSimulation( inputs3 ); html += "Running third simulation with " + sc3 + " servers...<br>"; info.innerHTML += html return simulation3.getOutputsAndRunIfAbsent(); }) .then( outputs3 => { let su3 = outputs3.value( "Utilization|Server utilization" ); let html = "Third simulation completed.<br>"; html += "With " + sc3 + " servers, Server utilization = " + su3 + "<br>"; info.innerHTML += html }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error( error ); }) .finally( () => { runButton.disabled = false; }); }
-
Попробуйте: Нестандартный поток операций
В этом сценарии мы сначала выполняем параллельно два прогона эксперимента с параметром Server Capacity, равным 4 в одном прогоне и 9 в другом. Два запуска инициируются вызовом функций simulation1.getOutputsAndRunIfAbsent() и simulation2.getOutputsAndRunIfAbsent(). Функция getOutputsAndRunIfAbsent() (как и все функции AnyLogic Cloud JavaScript API, связанные с коммуникацией с сервером) является асинхронной — она сразу возвращает промис. Далее нужно указать функцию-обработчик (handler) в блоке then. В этом случае возвращается два промиса для двух прогонов — нужно дождаться завершения обоих. С помощью функции Promise.all() возвращается один промис, который разрешается после того, как будут разрешены все промисы (в нашем случае переданные как итерируемый массив). Выходные данные параллельных прогонов экспериментов также возвращаются в виде массива в том же порядке. В следующем блоке then мы анализируем значения использования сервера в обоих прогонах и на основе этих значений настраиваем входные данные для третьего прогона эксперимента.
Когда вы параллельно запускаете несколько экспериментов вручную, как в этом примере, каждый вызов ModelRun.getOutputsAndRunIfAbsent() или ModelRun.waitForCompletion() выполняет свой собственный независимый опрос. Много параллельных запусков могут привести к высокому HTTP-трафику. Если есть такие опасения, попробуйте изменить значение параметра pollingPeriod этих функций. -
Запуск эксперимента варьирования параметров
-
В этом примере показано, как запустить эксперимент варьирования параметров. Один из входных параметров будет варьироваться в дискретном диапазоне. Чтобы продемонстрировать еще одну функцию AnyLogic Cloud API, возьмем входные значения существующего эксперимента из AnyLogic Cloud и изменим значение параметра со скаляра на диапазон.
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Parallel Simulations</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runVariation()">Run variation</button> <div id="info">The parameter variation results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let info; window.onload = () => { runButton = document.getElementById( "run-button" ); info = document.getElementById( "info" ); }; function runVariation() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Service System Demo" ) .then( version => { return cloudClient.createInputsFromExperiment( version, "Baseline" ); }) .then( inputs => { inputs.setRangeInput( "Mean service time", 1.8, 2, 0.1 ); let variation = cloudClient.createParameterVariation( inputs ); info.innerHTML = "Running parameter variation...<br>"; return variation.getOutputsAndRunIfAbsent( ["Total time in system|Total time in system"] ); }) .then( outputs => { let html = "Parameter variation completed.<br>"; let invalues = outputs.getValuesOfInput("Mean service time"); let outvalues = outputs.getValuesOfOutput("Total time in system|Total time in system"); for( let i=0; i<invalues.length; i++ ) { html += "When Mean service time = " + invalues[i] + ", mean Total time in system = " + outvalues[i].statistics.mean + "<br>" } info.innerHTML += html }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error( error ); }) .finally( () => { runButton.disabled = false; }); }
-
Попробуйте: Варьирование параметров
Чтобы повторно использовать набор входных данных из эксперимента в AnyLogic Cloud, мы используем функцию CloudClient.createInputsFromExperiment() вместо createDefaultInputs(). Скопировав входные данные эксперимента "Baseline", мы изменяем входные данные "Mean service time" на диапазонный тип (от 1,8 до 2,0 с шагом 0,1), вызвав функцию Inputs.setRangeInput(). Это означает, что будет выполнено три прогона эксперимента.
Затем нужно создать объект ModelRun типа вариации параметров. Для этого мы выполняем функцию CloudClient.createParameterVariation().
Запуск эксперимента с вариацией параметров вызывается функцией getOutputsAndRunIfAbsent() точно так же, как и в предыдущих примерах, но есть одно важное отличие. Все выходные данные экспериментов с несколькими прогонами могут представлять собой очень большой фрагмент данных, поэтому пользователь API должен четко указать, какие выходные данные нужны. Для этого нужно указать в качестве параметра имена выходных данных в массиве в функциях getOutputsAndRunIfAbsent() или getOutputs(). В этом примере показаны выходные данные "Total time in system|Total time in system". Если параметр не указан для эксперимента с несколькими прогонами, возвращаются только скалярные выходные данные, если таковые имеются.
Выходные данные эксперимента с несколькими прогонами возвращаются в виде объекта MultiRunOutputs, который имеет ряд функций, упрощающих навигацию. В этом простом примере мы получаем массив входных значений и соответствующий массив выходных значений и отображаем их.
Запуск Монте-Карло 1-го порядка
-
Запустим эксперимент Монте-Карло 1-го порядка на примере данной модели с четко заданным количеством репликаций. Мы будем использовать входные значения существующего простого эксперимента из веб-интерфейса AnyLogic Cloud.
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Monte Carlo 1st order</title> <script src="https://cloud.anylogic.com/assets/js-client-1.1/cloud-client.js"></script> <script src="js/main.monte_carlo_first.js"></script> </head> <body> <p> Enter the name of the model: </p> <p> <input type="text" id="model-name" placeholder="Model Name" value="Service System Demo" /> </p> <p> Set the number of replications: </p> <p> <input type="number" id="number-of-replications" placeholder="Number of replications" value="3"/> </p> <p> <button id="run-button" onclick="runMonteCarlo()">Run MonteCarlo</button> </p> <div id="info">The Monte Carlo 1<sup>st</sup> order results will be displayed here</div> </body> </html>
let cloudClient = CloudClient.create( "e05a6efa-ea5f-4adf-b090-ae0ca7d16c20" ); let runButton; let runButton2; let info; let modelName; let numberOfReplications; window.onload = () => { modelName = document.getElementById( "model-name" ); runButton = document.getElementById( "run-button" ); runButton2 = document.getElementById( "run-button2" ); info = document.getElementById( "info" ); numberOfReplications = document.getElementById("number-of-replications"); }; function runMonteCarlo() { runButton.disabled = true; cloudClient.getLatestModelVersion( modelName.value ) .then( version => { return cloudClient.createInputsFromExperiment( version, "Baseline" ); }) .then( inputs => { inputs.setInput( "Mean service time", 2); inputs.setNumberOfReplications(numberOfReplications.value); let monteCarlo = cloudClient.createMonteCarloFirstOrder( inputs ); info.innerHTML = "Running Monte Carlo 1st order...<br>"; //for a multi run, we have to explicitly name the outputs of interest return monteCarlo.getOutputsAndRunIfAbsent( ); }) .then( outputs => { let html = "Monte Carlo 1st order completed.<br>"; let outvalues = outputs.getValuesOfOutput("Mean queue size|Mean queue size"); html += "Mean queue size = " + outvalues.statistics.mean + "<br>" info.innerHTML += html }) .catch( error => { info.innerHTML = error.status + "<br>" + error.message; console.error( error ); }) .finally( () => { runButton.disabled = false; }); }
-
Попробуйте: Запуск Монте-Карло 1-го порядка
В HTML-коде есть два поля: в первом вы указываете название модели для общедоступной версии Cloud, а во втором — количество репликаций для эксперимента Монте-Карло 1-го порядка.
Указав необходимую информацию, щелкните по кнопке для выполнения эксперимента.
Cloud запускает эксперимент с заданным количеством репликаций. Выходные данные эксперимента с несколькими прогонами возвращаются в виде объекта MultiRunOutputs, который имеет ряд функций, упрощающих навигацию — как в примере, где мы используем функцию getValuesOfOutput() для запроса среднего значения указанных выходных данных, которое затем отображается в окне браузера.
-
Простой эксперимент с анимацией (простой)
-
В этом примере показано, как встроить анимацию облачной модели в веб-страницу.
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Run animation. Minimalistic</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runAnimation()">Run animation</button> <div id="animation-container" style="width: 1200px; height: 700px; border: 1px solid blue;"> </div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); function runAnimation() { runButton = document.getElementById( "run-button" ); runButton.disabled = true; cloudClient.getLatestModelVersion( "Bass Diffusion Demo 8.5.0" ) .then( version => { let inputs = cloudClient.createDefaultInputs( version ); inputs.setInput( "Contact Rate", 30 ); return cloudClient.startAnimation( inputs, "animation-container" ); }) .then( animation => { return animation.waitForCompletion(); }) .catch( error => { console.error( error ); }) .finally( () => { runButton.disabled = false; }); }
-
Попробуйте: Запуск анимации
В коде HTML вы должны создать поля для заполнения анимации. В этом примере это изначально пустой элемент <div> 1200x700 с идентификатором "animation-container". Затем, когда пользователь щелкает по кнопке Запустить, вызывается функция runAnimation(). Функция отключает кнопку, ищет последнюю версию модели, создает набор входных данных по умолчанию и изменяет одно из входных значений. Вызов функции cloudClient.startAnimation() запускает модель, подключает модель к внешнему интерфейсу и запускает потоковую передачу анимации в предоставленный контейнер (container). Этот вызов завершается по мере завершения HTTP-запроса и возвращает промис с объектом Animation. Затем используется функция animation.waitForCompletion(), чтобы дождаться, когда пользователь щелкнет по кнопке Стоп.
Даже если анимация эксперимента завершилась (например, достигается время остановки), эксперимент не считается остановленным до тех пор, пока не произойдет одно из следующих событий:- Пользователь щелкнет по кнопке Стоп на панели управления анимацией.
- Происходит остановка со стороны сервера (по какой-либо причине)
-
Запуск анимации с кнопками паузы и возобновления и опросом статуса
-
В этом примере есть кнопки для паузы и возобновления эксперимента. Ключевыми функциями объекта Animation, используемыми здесь, являются pause(), resume() и getState().
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Animation. Pause Resume</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runAnimation()">Run animation</button> <button id="pause-button" onclick="pauseAnimation()" disabled>Pause</button> <button id="resume-button" onclick="resumeAnimation()" disabled>Resume</button> <div id="animation-container" style="width: 1200px; height: 700px; border: 1px solid blue;"> </div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let pauseButton; let resumeButton; let animation; window.onload = () => { runButton = document.getElementById( "run-button" ); pauseButton = document.getElementById( "pause-button" ); resumeButton = document.getElementById( "resume-button" ); }; function runAnimation() { runButton.disabled = true; cloudClient.getModelByName( "Bass Diffusion Demo 8.5.0" ) .then( model => cloudClient.getLatestModelVersion( model ) ) .then( version => { let inputs = cloudClient.createDefaultInputs( version ); inputs.setInput( "Contact Rate", 40 ); return cloudClient.startAnimation( inputs, "animation-container" ); }) .then( a => { animation = a; startPolling(); return animation.waitForCompletion(); }) .catch( error => { console.error( error ); }) .finally( () => { stopPolling(); runButton.disabled = false; pauseButton.disabled = true; resumeButton.disabled = true; }); } function pauseAnimation() { pauseButton.disabled = true; animation.pause(); } function resumeAnimation() { resumeButton.disabled = true; animation.resume(); } let pollingInterval; function startPolling() { pollingInterval = setInterval( () => { animation.getState() .then( state => { pauseButton.disabled = state != "RUNNING"; resumeButton.disabled = state != "PAUSED"; }); }, 500 ); } function stopPolling() { clearInterval( pollingInterval ); }
-
Попробуйте: Анимация. Пауза и возобновление
В коде HTML есть две новые кнопки над контейнером анимации, которые изначально отключены. В JavaScript мы запоминаем эти элементы по мере загрузки страницы. Мы также запоминаем объект Animation, возвращаемый промисом с cloudClient.startAnimation(). Действия, закрепленные за кнопками, просто вызывают pause() и resume() этого объекта. Как только запускается анимация, начинается опрос о статусе каждые 0,5 секунды, см. функцию startPolling(). Вызов getState() возвращает промис со статусом анимации, и мы используем его для включения или отключения кнопок. Опрос останавливается, когда останавливается модель или возникает ошибка, см. блок finally.
При прогоне анимации входные данные не проверяются до тех пор, пока они не передаются в модель. Поэтому, если есть ошибка во входных значениях (например, ошибка типа), модель не запустится, и появится сообщение об ошибке в окне анимации; блок catch не будет достигнут.Также в этом примере мы показываем другой, более общий способ получения последней версии модели: сначала мы получаем объект Model по имени, затем запрашиваем последнюю версию модели.
-
Прогон анимации с внешним управлением параметрами модели
-
В этом примере показано, как управлять входными параметрами модели во время прогона с помощью AnyLogic Cloud API и как вызывать функцию, заданную в модели. Запустим модель со значением входного параметра по умолчанию и предоставим внешние элементы управления HTML для изменения этого значения. Здесь используются ключевые функции setValue() и callFunction().
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Animation. Parameter Control</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.js"></script> </head> <body> <button id="run-button" onclick="runAnimation()">Run animation</button> <input id="parameter-range" onchange="changeParameter()" type="range" min="0" max="100" disabled> <button id="reset-button" onclick="resetParameter()" disabled>Reset parameter</button> <div id="animation-container" style="width: 1200px; height: 700px; border: 1px solid blue;"> </div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let parameterRange; let resetButton; let animation; window.onload = () => { runButton = document.getElementById( "run-button" ); parameterRange = document.getElementById( "parameter-range" ); resetButton = document.getElementById( "reset-button" ); }; function runAnimation() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Bass Diffusion Demo 8.5.0" ) .then( version => { let inputs = cloudClient.createDefaultInputs( version ); return cloudClient.startAnimation( inputs, "animation-container" ); }) .then( a => { animation = a; parameterRange.disabled = false; resetButton.disabled = false; return animation.waitForCompletion(); }) .catch( error => { console.error( error ); }) .finally( () => { runButton.disabled = false; parameterRange.disabled = true; resetButton.disabled = true; }); } function changeParameter() { animation.setValue( "experiment.root.ContactRate", parseFloat( parameterRange.value ) ); } function resetParameter() { parameterRange.value = 30; animation.callFunction( "experiment.root.set_ContactRate", [30] ); }
-
Попробуйте: Анимация. Управление параметрами
В HTML-коде есть ползунок и кнопка. Изначально эти элементы управления отключены.
Функция changeParameter() использует функцию API AnyLogic Cloud setValue(), первым параметром которой является путь к объекту, значение которого мы хотим установить.
Путь всегда должен начинаться со слова «experiment», за которым в большинстве случаев следует «root»: experiment.root ведет к агенту верхнего уровня модели. Обычно это (единственный) экземпляр класса Main. Поскольку параметр Contact Rate находится в Main, полный путь к нему такой: experiment.root.ContactRate.
Здесь мы используем оригинальное Java-имя параметра, а не его метку в интерфейсе Contact Rate.Кроме того, поскольку параметр является числовым, нужно преобразовать parameterRange.value, являющийся строкой, в число с плавающей точкой.
Подобным образом функция resetParameter() использует API функцию callFunction(), чтобы выставить значение Contact Rate на 30. Это делается с помощью вызова функции set_ContactRate(), заданной в классе модели Main (в данном случае функция была автоматически сгенерирована AnyLogic, но это также может быть и функция, заданная пользователем). Путь к функции, очевидно, experiment.root.set_ContactRate, а аргументы вызова функции должны передаваться в виде массива JavaScript. В нашем случае есть только один параметр — новое значение 30. Функции, заданные пользователем в модели, вызываются точно так же.
-
Получение информации во время прогона анимированной модели
-
В данном примере мы будем получать информацию о модели во время прогона с помощью функции getValue() объекта Animation.
HTML
JavaScript<!DOCTYPE html> <html lang="en"> <head> <title>AnyLogic Cloud API Example - Animation. Get data</title> <script src="https://cloud.anylogic.com/assets/js-client-8.5.0/cloud-client.js"></script> <script src="js/main.get_data.js"></script> </head> <body> <button id="run-button" onclick="runAnimation()">Run animation</button> <button id="get-scalar-button" onclick="getScalarValue()" disabled>Get scalar value</button> <button id="get-dataset-button" onclick="getDataSet()" disabled>Get dataset</button> <div id="info">The data retrieved from the model will be displayed here</div> <div id="animation-container" style="width: 1200px; height: 700px; border: 1px solid blue;"> </div> </body> </html>
let cloudClient = CloudClient.create("e05a6efa-ea5f-4adf-b090-ae0ca7d16c20"); let runButton; let getScalarButton; let getDataSetButton; let info; let animation; window.onload = () => { runButton = document.getElementById( "run-button" ); getScalarButton = document.getElementById( "get-scalar-button" ); getDataSetButton = document.getElementById( "get-dataset-button" ); info = document.getElementById( "info" ); }; function runAnimation() { runButton.disabled = true; cloudClient.getLatestModelVersion( "Bass Diffusion Demo 8.5.0" ) .then( version => { let inputs = cloudClient.createDefaultInputs( version ); return cloudClient.startAnimation( inputs, "animation-container" ); }) .then( a => { animation = a; getScalarButton.disabled = false; getDataSetButton.disabled = false; return animation.waitForCompletion(); }) .catch( error => { info.innerText = error.message; console.error( error ); }) .finally( () => { runButton.disabled = false; getScalarButton.disabled = true; getDataSetButton.disabled = true; }); } function getScalarValue() { let value = animation.getValue( "experiment.root.Adopters" ) .then( value => { info.innerText = "Adopters = " + value; }); } function getDataSet() { let value = animation.getValue( "experiment.root._ds_Adopters" ) .then( value => { info.innerText = "Adopters over time: time=[" + value.dataX + "] Adopters=[" + value.dataY + "]"; }); }
-
Попробуйте: Анимация. Получение данных
В HTML-коде есть две кнопки: одна для запроса скалярного значения, другая для запроса набора данных (обе кнопки изначально отключены), а также элемент <div> для отображения полученной информации.
Первый параметр getValue() — это полный путь к объекту, к которому осуществляется доступ. Путь начинается с experiment.root (точно так же, как для setValue() и callFunction() в предыдущем примере). Скалярное значение — это переменная системной динамики Adopters, а набор данных — это те данные, которые автоматически создаются для той же переменной (в AnyLogic такие наборы данных генерируются автоматически и имеют префикс _ds_. Если у вас есть набор данных, заданных пользователем, вам, очевидно, следует использовать имя этого набора данных).
Структура объекта, возвращаемого функцией getValue(), зависит от его типа. Для примитивных типов это просто. Чтобы узнать больше о сложных типах, см. раздел Data conversion.
В этом примере Java объект AnyLogic DataSet преобразуется в объект JSON с полями dataX и dataY. Если бы у нас была пользовательская диаграмма (например, диаграмма Plotly или Tableau) как часть внешнего интерфейса, мы могли бы вводить эти данные в диаграмму для их визуализации, возможно, с обновлением в режиме реального времени с определенной частотой.
-
Как мы можем улучшить эту статью?
-