[{"data":1,"prerenderedAt":582},["ShallowReactive",2],{"/hpc":3,"/hpc-surround":571},{"id":4,"title":5,"body":6,"description":538,"extension":539,"meta":540,"navigation":558,"path":567,"seo":568,"stem":569,"__hash__":570},"content/hpc.md","Cluster Computing (HPC)",{"type":7,"value":8,"toc":523},"minimark",[9,21,30,67,75,78,92,103,106,113,116,132,141,151,158,165,180,185,191,200,203,220,223,229,232,274,277,282,288,293,299,305,312,315,318,321,330,333,341,354,363,374,381,384,390,394,400,404,412,421,431,433,439,442,479,483,489,493,499,509,515],[10,11,15],"h1",{"id":12,"className":13},"cluster-computing-hpc",[14],"section-heading",[16,17,5],"a",{"className":18,"href":20},[19],"section-anchor","#cluster-computing-hpc",[22,23,24,25,29],"p",{},"This document is an advanced guide that provides examples of how to run NetLogo BehaviorSpace experiments on a High-Performance Computing (HPC) cluster. The scripts provided in this guide are specifically for ",[26,27,28],"strong",{},"Slurm",", a popular open-source workload manager and job scheduler, but they can be adapted for use with other schedulers.",[31,32,35,45],"div",{"className":33},[34],"toc",[36,37,40],"h4",{"id":38,"className":39},"table-of-contents",[14],[16,41,44],{"className":42,"href":43},[19],"#table-of-contents","Table of Contents",[46,47,48,55,61],"ul",{},[49,50,51],"li",{},[16,52,54],{"href":53},"#installing-netlogo-on-a-cluster","Installing NetLogo on a Cluster",[49,56,57],{},[16,58,60],{"href":59},"#submitting-a-job","Submitting a Job",[49,62,63],{},[16,64,66],{"href":65},"#advanced-usage","Advanced Usage",[68,69,72],"h2",{"id":70,"className":71},"installing-netlogo-on-a-cluster",[14],[16,73,54],{"className":74,"href":53},[19],[22,76,77],{},"To run BehaviorSpace experiments, NetLogo must be installed on your HPC in a location accessible to the user.",[46,79,80,89],{},[49,81,82,83,88],{},"The easiest method is to download the desired NetLogo version (for most clusters this is the 64-bit Linux installation, available at ",[16,84,85],{"href":85,"rel":86},"https://www.netlogo.org/downloads/linux/",[87],"nofollow",") , unzip and move the entire folder to a directory on your HPC.",[49,90,91],{},"Alternatively, you can install NetLogo from the command line if your HPC allows it. For example, you can download and unzip the 64-bit Linux version of NetLogo 7.0.0 with:",[93,94,100],"pre",{"className":95,"code":97,"language":98,"meta":99},[96],"language-bash","curl -O https://ccl.northwestern.edu/netlogo/7.0.0/NetLogo-7.0.0-64.tgz\ntar zxf NetLogo-7.0.0-64.tgz\n","bash","",[101,102,97],"code",{"__ignoreMap":99},[22,104,105],{},"Note: Although NetLogo comes with a bundled Java installation, some HPC clusters require users to run only approved Java Runtime Environments (JREs). If that is the case, you must ensure that your HPC has a compatible JRE (Java 17 or higher). Please consult your HPC documentation or system administrator if unsure.",[68,107,110],{"id":108,"className":109},"submitting-a-job",[14],[16,111,60],{"className":112,"href":59},[19],[22,114,115],{},"This section provides two examples of how to run a BehaviorSpace experiment on an HPC using Slurm.",[117,118,119,126],"ol",{},[49,120,121,122,125],{},"A ",[26,123,124],{},"simple script",", which must be customized for each experiment and model.",[49,127,121,128,131],{},[26,129,130],{},"general script",", which takes arguments to automatically generate and submit a Slurm job script.",[22,133,134,135,140],{},"The simple script is easier to debug, while the general script is more convenient for repeated use. Both approaches are valid, and the scripts can also be found ",[16,136,139],{"href":137,"rel":138},"https://github.com/umit1010/slurm-scripts-for-netlogo",[87],"here on GitHub",".",[142,143,146],"h3",{"id":144,"className":145},"a-simple-example",[14],[16,147,150],{"className":148,"href":149},[19],"#a-simple-example","A simple example",[22,152,153,154,157],{},"The script below is a simple Slurm job submission template for NetLogo. Lines beginning with ",[101,155,156],{},"###"," provide explanations.",[22,159,160,161,164],{},"Save this script as ",[101,162,163],{},"simple_standalone_job.sh",". After updating it to match your HPC configuration, model, and experiment, you can submit it with:",[22,166,167],{},[101,168,169,176,177],{},[170,171,175],"span",{"className":172},[173,174],"token","variable","sbatch"," ",[170,178,163],{"className":179},[173,174],[22,181,182],{},[26,183,184],{},"Script:",[93,186,189],{"className":187,"code":188,"language":98,"meta":99},[96],"#!/bin/sh\n\n### ---\n### simple_standalone_job.sh\n### ---\n\n### Template standalone Slurm job submission script for NetLogo BehaviorSpace experiments\n\n#SBATCH --account=PROJECTID       ### replace PROJECTID with your allocation/project ID number.\n#SBATCH --partition=short         ### replace short with desired parition: medium, long, gengpu, etc.\n#SBATCH --time=1:30:00            ### time format is hh:mm:ss\n#SBATCH --nodes=1                 ### leave the --nodes as 1 because NetLogo can run into problems when trying to use multiple nodes\n#SBATCH --ntasks-per-node=16      ### replace 16 with the number of CPU cores you will request\n#SBATCH --mem=4G                  ### replace 4G with the amount of memory you will request; do not forget to put specify the units.\n#SBATCH --job-name=EXAMPLE_JOB    ### replace EXAMPLE_JOB with the name of your job (can be anything)\n#SBATCH --output=%x-%j.out        ### automatically generates an output file. Slurm replaces %x with job name you provided in the previous instruction and %j with the unique job id.\n#SBATCH --error=%x-%j.err         ### automatically generates an error file.\n#SBATCH --mail-type=ALL           ### replace ALL with BEGIN, END, or FAIL if you'd like to.\n#SBATCH --mail-user=U@SCHOOL.EDU  ### Replace U@SCHOOL.edu with your own email address so that Slurm can send you emails when your job is queried, started, completed, or terminated due to an error.\n\nmodule purge all\nmodule load java/jdk-17.0.2+8     ### You may need to update this line if your HPC doesn't have the jdk-17.0.2+8 module available.\n\nJVM_OPTS=(-Xmx1024m -server -XX:+UseParallelGC -Dfile.encoding=UTF-8 -Dnetlogo.extensions.dir=\"${BASE_DIR}/extensions\")\n\n### Make sure to update the NetLogo installation path, experiment name, model filename, experiment name and output filename variables in the following command.\njava ${JVM_OPTS[@]} -classpath PATH/TO/NETLOGO/lib/app/netlogo-7.0.0.jar org.nlogo.headless.Main --model \"MODELFILE.nlogo\" --experiment \"EXPERIMENT_NAME\" --threads 16 --table PATH/TO/OUT/FOLDER/OUTPUTFILE.csv\n",[101,190,188],{"__ignoreMap":99},[142,192,195],{"id":193,"className":194},"a-more-general-example",[14],[16,196,199],{"className":197,"href":198},[19],"#a-more-general-example","A more general example",[22,201,202],{},"Editing a submission file for each experiment can be tedious. The following scripts automate the process by generating a temporary job script with your chosen arguments and then submitting it.",[22,204,205,206,209,210,213,214,216,217,219],{},"Save the following as ",[101,207,208],{},"config.sh"," and ",[101,211,212],{},"generate_and_submit.sh",". Update ",[101,215,208],{}," with your account details, and adjust ",[101,218,212],{}," as needed for your HPC.",[22,221,222],{},"Run the script with:",[93,224,227],{"className":225,"code":226,"language":98,"meta":99},[96],"bash generate_and_submit.sh \u003Cmodel-file> \u003Cexperiment-name> \u003Ccategory> \u003Cmaxtime> \u003Cthreads> \u003Cram>\n",[101,228,226],{"__ignoreMap":99},[22,230,231],{},"Where the command-line arguments are:",[46,233,234,240,245,251,262,268],{},[49,235,236,239],{},[101,237,238],{},"model-file"," (including the file extension)",[49,241,242],{},[101,243,244],{},"experiment-name",[49,246,247,250],{},[101,248,249],{},"category"," (which partition to use: short, normal, long, gpu, etc.)",[49,252,253,256,257,261],{},[101,254,255],{},"maxtime"," (in ",[258,259,260],"em",{},"hh:mm:ss"," format)",[49,263,264,267],{},[101,265,266],{},"threads"," (number of CPU cores to request)",[49,269,270,273],{},[101,271,272],{},"ram"," (in megabytes)",[22,275,276],{},"This will automatically generate an intermediary bash script and then use it to submit the job. It will also delete the intermediary file after submission to prevent folder pollution.",[22,278,279],{},[26,280,281],{},"Example:",[93,283,286],{"className":284,"code":285,"language":98,"meta":99},[96],"bash generate_and_submit.sh fire.nlogo densityexp short 1:00:00 32 4096\n",[101,287,285],{"__ignoreMap":99},[22,289,290],{},[26,291,292],{},"Scripts:",[93,294,297],{"className":295,"code":296,"language":98,"meta":99},[96],"#!/bin/bash\n\n### ---\n### config.sh\n### ---\n\n# Update this script with your Slurm account information\n\n# your email address to receive notifications\nemail=youremail@yourinstitution.edu\n\n# The following variable should match your Slurm Allocation/Project ID\nproject=p00000\n\n# the experiment directory (absolute path)\npath=/home/username/projectfolder\n",[101,298,296],{"__ignoreMap":99},[93,300,303],{"className":301,"code":302,"language":98,"meta":99},[96],"#!/bin/bash\n\n### ---\n### generate_and_submit.sh\n### ---\n\n### A script to automate the slurm job submission process for NetLogo BehaviorSpace experiments\n\nmodel=$1\nexperiment=$2\ncategory=$4\nmaxtime=$5\nthreads=$6\nram=$7\n\n# NetLogo struggles to divide experiments between multiple physical processors\nmachines=1\n\n# load the config file to pull the shared variables\nsource config.sh\n\n### AUTO GENERATE A TEMPORARY SCRIPT TO RUN THE EXPERIMENT\n### This approach minimizes the repetitive editing and potential errors\n### that may arise from trying to manually edit long scripts\n\ntotalram=$((ram*threads+4096))\nmodelpath=${path}/${model}\n\nrunfile=run_${experiment}.sh\n\n# if a file with the same name exists, just delete it\nif test -f $runfile ; then\n    rm $runfile\nfi\n\n# create the slurm job definition within the run file\necho \"#!/bin/sh\" >> $runfile\necho \"#SBATCH --account=\"${project} >> $runfile\necho \"#SBATCH --partition=\"${category} >> $runfile\necho \"#SBATCH --time=\"${maxtime} >> $runfile\necho \"#SBATCH --nodes=\"${machines} >> $runfile\necho \"#SBATCH --ntasks-per-node=\"${threads} >> $runfile\necho \"#SBATCH --mem=\"$((totalram/1024))G >> $runfile\necho \"#SBATCH --job-name=\"${experiment} >> $runfile\necho \"#SBATCH --output=output_%x-%j.out\" >> $runfile\necho \"#SBATCH --mail-type=\"ALL >> $runfile\necho \"#SBATCH --mail-user=\"${email} >> $runfile\n\necho \"module purge all\" >> $runfile\necho \"module load java/jdk-17.0.2+8\" >> $runfile\n\necho \"JVM_OPTS=(-Xmx${totalram}m -server -XX:+UseParallelGC -Dfile.encoding=UTF-8 -Dnetlogo.extensions.dir=\"${BASE_DIR}/extensions\")\" >> $runfile\n\necho \"java ${JVM_OPTS[@]} -classpath ${path}/netlogo/lib/app/netlogo-7.0.0.jar org.nlogo.headless.Main --model ${modelpath} --setup-file ${path}/xml/${experiment}.xml --threads $threads --table ${path}/csv/${experiment}.csv\" >> $runfile\n\necho \"Job ID: \"\n\n# submit the job and print the job number\nsbatch --parsable $runfile\n\n# remove the temporary run file to keep things clean\nrm $runfile\n",[101,304,302],{"__ignoreMap":99},[68,306,309],{"id":307,"className":308},"advanced-usage",[14],[16,310,66],{"className":311,"href":65},[19],[22,313,314],{},"NetLogo includes built-in parallelization, but this often does not integrate well with multi-node HPC architectures. Large BehaviorSpace experiments with many parameter combinations and repetitions that require hundreds or thousands of runs may crash if distributed directly across multiple nodes.",[22,316,317],{},"A better strategy is to split the experiment into many small jobs (one per parameter combination and repetition).",[22,319,320],{},"To do so, first we need to subdivide our NetLogo BehaviorSpace experiment into separate BehaviorSpace experiment files (xml files) for each parameter combination.",[142,322,325],{"id":323,"className":324},"dividing-behaviorspace-experiments-into-smaller-sub-experiments",[14],[16,326,329],{"className":327,"href":328},[19],"#dividing-behaviorspace-experiments-into-smaller-sub-experiments","Dividing BehaviorSpace experiments into smaller sub-experiments",[22,331,332],{},"This step can be performed on your local machine, not necessarily on an HPC.",[117,334,335],{},[49,336,337,338,140],{},"Export your BehaviorSpace experiment as an XML file. In BehaviorSpace, select your experiment and click ",[258,339,340],{},"Export",[22,342,343],{},[344,345],"img",{"alt":346,"className":347,"src":349,"width":350,"height":351,"style":352},"hpc/export.png",[348],"netlogo-image","/_content/images/hpc/export.png",410,327,{"aspectRatio":353},"410/327",[46,355,356],{},[49,357,358,359,362],{},"For maximum parallelization, set repetitions to ",[26,360,361],{},"1"," before exporting. This allows submitting a separate job for each repetition.",[117,364,366],{"start":365},2,[49,367,368,369,140],{},"Use the exported XML file to generate individual experiment files. Instructions and a Jupyter notebook can be found ",[16,370,373],{"href":371,"rel":372},"https://github.com/can-gurkan/BehaviorSpace_exp_split",[87],"here",[22,375,376,377,380],{},"Alternatively, you can run the Python script below (",[101,378,379],{},"split_bspace_exps.py",") if you have Python installed on your machine. It is the same script linked above which generates one XML experiment file per parameter combination.",[22,382,383],{},"Run as:",[93,385,388],{"className":386,"code":387,"language":98,"meta":99},[96],"python split_bspace_exps.py \u003Cinput_file_name> \u003Coutput_folder_path>\n",[101,389,387],{"__ignoreMap":99},[22,391,392],{},[26,393,281],{},[93,395,398],{"className":396,"code":397,"language":98,"meta":99},[96],"python split_bspace_exps.py /path/to/example-experiment.xml /path/to/output/folder/\n",[101,399,397],{"__ignoreMap":99},[22,401,402],{},[26,403,184],{},[93,405,410],{"className":406,"code":408,"language":409,"meta":99},[407],"language-python","\"\"\"split_bspace_exps.py\n\nThis script splits a NetLogo BehaviorSpace experiment into multiple experiments, each with a different set of parameters.\nThe inputs are a BehaviorSpace experiment xml file and the output folder path.\nThe output is a folder with the new experiments, one for each combination of parameters.\n\nUsage: python split_bspace_exps.py \u003Cinput_file_name> \u003Coutput_folder_path>\nExample: python split_bspace_exps.py /path/to/example-experiment.xml /path/to/output/folder/\n\"\"\"\n\nimport sys\nimport xml.etree.ElementTree as ET\nfrom itertools import product\nfrom pathlib import Path\n\ndef dict_product(d):\n    \"\"\"\n    Given a dictionary of parameters and their values, return a generator that yields a dictionary for each combination of parameters.\n    \"\"\"\n    keys = d.keys()\n    for element in product(*d.values()):\n        yield dict(zip(keys, element))\n\ndef construct_pdict(file_name):\n    \"\"\"\n    Given a BehaviorSpace experiment xml file, return a dictionary of parameters and their values.\n    \"\"\"\n    tree = ET.parse(file_name)\n    root = tree.getroot()\n    pdict = {}\n    for node in root.findall('.//enumeratedValueSet'):\n        plist = []\n        for child in node:\n            plist.append(child.attrib.get('value'))\n        if len(plist) > 1:\n            pdict[node.get('variable')] = plist\n    for node in root.findall('.//steppedValueSet'):\n        rstart = node.attrib.get('first')\n        rend = node.attrib.get('last')\n        rstep = node.attrib.get('step')\n        plist = range(int(rstart), int(rend)+int(rstep), int(rstep))\n        pdict[node.get('variable')] = [str(num) for num in plist]\n    print(pdict)\n    return pdict\n\ndef process_xml(file, dict, new_folder):\n    \"\"\"\n    Given a BehaviorSpace experiment xml file, a dictionary of parameters and their values, and a new folder,\n    create a new experiment xml file for each combination of parameters and save it to the new folder.\n    \"\"\"\n    tree = ET.parse(file)\n    root = tree.getroot()\n    counter = 0\n    name_list = []\n    Path(new_folder).mkdir(parents=True, exist_ok=True)\n    for cd in dict_product(dict):\n        exp_name_str = 'exp' + str(counter)\n        name_list.append([exp_name_str,list(cd.values())])\n        root[0].set('name', exp_name_str)\n\n        for k,v in cd.items():\n            # first delete all elements matching the tag\n            elements_to_remove = root.findall('.//*[@variable=\"'+k+'\"]')\n            for element in elements_to_remove:\n                # Iterate through the entire tree to find the parent of the current element\n                for parent in root.iter():\n                    if element in parent:\n                        parent.remove(element)\n                        break\n            # Now insert the appropriate elements\n            target_item = root.find('.//constants')\n            new_element_str = f'\u003CenumeratedValueSet variable=\"{k}\">\u003Cvalue value=\"{v}\">\u003C/value>\u003C/enumeratedValueSet>'\n            new_element = ET.fromstring(new_element_str)\n            target_item.append(new_element)\n\n        with open(new_folder+exp_name_str+'.xml', 'wb') as f:\n            ET.indent(root, space=\"  \")\n            tree.write(f, 'utf-8', xml_declaration=True)\n        counter += 1\n    print(f'{counter} experiments created')\n    print('\\nexp_name', list(cd.keys()))\n    for i in name_list:\n        print(i)\n\ndef split_exps(file_name,new_folder):\n    \"\"\"\n    Given a BehaviorSpace experiment xml file and a new folder,\n    construct a dictionary of parameters and their values,\n    and create a new experiment xml file for each combination of parameters and save it to the new folder.\n    \"\"\"\n    pdict = construct_pdict(file_name)\n    process_xml(file_name, pdict, new_folder)\n\ndef check_args(args):\n    \"\"\"\n    Given a list of arguments, check if the arguments are valid.\n    \"\"\"\n    if len(args) != 3:\n        print('Error: Invalid number of arguments')\n        print('Usage: python split_bspace_exps.py \u003Cinput_file_name> \u003Coutput_folder_path>')\n        print('Example: python split_bspace_exps.py /path/to/example-experiment.xml /path/to/output/folder/')\n        sys.exit(1)\n    if not Path(args[1]).exists():\n        print('Error: input_file_name does not exist')\n        sys.exit(1)\n\n\nif __name__ == '__main__':\n\n    check_args(sys.argv)\n    split_exps(sys.argv[1], sys.argv[2])\n    print('Done')\n","python",[101,411,408],{"__ignoreMap":99},[142,413,416],{"id":414,"className":415},"submitting-separate-jobs-for-each-experiment-file",[14],[16,417,420],{"className":418,"href":419},[19],"#submitting-separate-jobs-for-each-experiment-file","Submitting separate jobs for each experiment file",[22,422,423,424,427,428,430],{},"Once you have a directory of XML files, you can use the script below (",[101,425,426],{},"deployment.bash",") to submit each as a separate job. It uses the ",[101,429,212],{}," script described earlier.",[22,432,383],{},[93,434,437],{"className":435,"code":436,"language":98,"meta":99},[96],"bash deployment.bash \u003Cexperiment-directory> \u003Cnetlogo-model> \u003Cnum-repetitions> \u003Ccategory> \u003Cmaxtime> \u003Cthreads> \u003Cram>\n",[101,438,436],{"__ignoreMap":99},[22,440,441],{},"Where the arguments are:",[46,443,444,450,455,461,465,471,475],{},[49,445,446,449],{},[101,447,448],{},"experiment-directory"," (path to directory that contains the xml files)",[49,451,452],{},[101,453,454],{},"netlogo-model",[49,456,457,460],{},[101,458,459],{},"num-repetitions"," (how many repetitions to run for each experiment. note that this should be 1 if you did not edit the number of repetitions in your experiment before exporting)",[49,462,463,250],{},[101,464,249],{},[49,466,467,256,469,261],{},[101,468,255],{},[258,470,260],{},[49,472,473,267],{},[101,474,266],{},[49,476,477,273],{},[101,478,272],{},[22,480,481],{},[26,482,281],{},[93,484,487],{"className":485,"code":486,"language":98,"meta":99},[96],"bash deployment.bash /directory/of/xmls/ fire.nlogo 1 short 1:00:00 1 4096\n",[101,488,486],{"__ignoreMap":99},[22,490,491],{},[26,492,184],{},[93,494,497],{"className":495,"code":496,"language":98,"meta":99},[96],"### ---\n### deployment.bash\n### ---\n\nif [ $# -ne 7 ]\nthen\n  echo \"Usage 'bash deployment.bash /directory/of/xmls/ /path/to/model.nlogo number-of-reps partition max-time threads memory'\"\n  exit 1\nfi\n\n#XML_DIR= directory of BehaviorSpace exoeriment files\nXML_DIR=$1\n#MODEL= path to NetLogo model\nMODEL=$2\n#REPS= number of repetitions for each experiment\nREPS=$3\n#CATEGORY= partition\nCATEGORY=$4\n#MAXTIME= time limit\nMAXTIME=$5\n#THREADS= number of cpus (should be 1 in general)\nTHREADS=$6\n#RAM= max ram for each cpu in mb\nRAM=$7\n\nfor iter in $(seq 1 $REPS); do\n  for SETUPFILE in $(ls ${XML_DIR}/*.xml); do\n    EXPR=\"$(basename ${SETUPFILE%.*})\"\n    #echo $SETUPFILE\n    #echo $EXPR\n    bash generate_and_submit.sh $MODEL $SETUPFILE $CATEGORY $MAXTIME $THREADS $RAM;\n    sleep 2 # Avoid overloading the scheduler\n  done\ndone\n",[101,498,496],{"__ignoreMap":99},[22,500,501,504,505,508],{},[26,502,503],{},"Note:"," This script inserts a 2-second pause after each submission to avoid overwhelming the scheduler. For very large experiments, consider running it in the background with ",[101,506,507],{},"screen",". For example:",[93,510,513],{"className":511,"code":512,"language":98,"meta":99},[96],"screen -dmS session_name bash deployment.sh /directory/of/xmls/ fire.nlogo short 1:00:00 1 4096\n",[101,514,512],{"__ignoreMap":99},[22,516,517,518,140],{},"The most up-to-date versions of these scripts, along with additional utilities and scripts, can be found ",[16,519,522],{"href":520,"rel":521},"https://github.com/can-gurkan/BehaviorSpace-HPC",[87],"on BehaviorSpace HPC GitHub Repository",{"title":99,"searchDepth":524,"depth":525,"links":526},5,3,[527,529,530,534],{"id":38,"depth":528,"text":44},4,{"id":70,"depth":365,"text":54},{"id":108,"depth":365,"text":60,"children":531},[532,533],{"id":144,"depth":525,"text":150},{"id":193,"depth":525,"text":199},{"id":307,"depth":365,"text":66,"children":535},[536,537],{"id":323,"depth":525,"text":329},{"id":414,"depth":525,"text":420},"An advanced guide on running NetLogo BehaviorSpace experiments on High-Performance Computing (HPC) clusters using Slurm job scheduler.","md",{"source":541,"metadataOutputPath":542,"projectConfig":543,"language":550,"inheritFrom":559,"output":558,"version":544,"keywords":560,"tags":564,"icon":565,"assetsRoot":566},"autogen/hpc.md","content/hpc.metadata.yaml",{"version":544,"projectRoot":140,"scanRoot":545,"outputRoot":546,"defaults":547,"engine":553,"partials":554,"dedupeIdenticalDiskWrites":558},"7.0.4","autogen","content",{"inheritFrom":548,"language":550,"output":551,"extension":539,"title":552,"version":544},[549],0,"en",false,"NetLogo User Manual","handlebars",{"directoryPaths":555,"extensions":556},[140],[557,539],"mustache",true,[549],[561,562,563,28],"HPC","High-Performance Computing","Cluster Computing",[561,562,563],"i-lucide-server-cog","/home/runner/work/Helio/Helio/apps/docs/autogen","/hpc",{"title":5,"description":538},"hpc","doBAQBaxLOSk42ayBWCcIdiLa6h4v5DBu8ggbCz0IMk",[572,577],{"title":573,"path":574,"stem":575,"description":576},"GoGo Extension Dictionary: talk-to-servo-ports","/gogo/talk-to-servo-ports","gogo/talk-to-servo-ports","Documentation for the talk-to-servo-ports primitive.",{"title":578,"path":579,"stem":580,"description":581},"HubNet","/hubnet","hubnet","HubNet is a technology that lets you use NetLogo to run participatory simulations in the classroom where multiple users can interact with the model.",1777657789465]