-
Notifications
You must be signed in to change notification settings - Fork 38
Expand file tree
/
Copy pathUserGuide.dox
More file actions
executable file
·1972 lines (1349 loc) · 125 KB
/
UserGuide.dox
File metadata and controls
executable file
·1972 lines (1349 loc) · 125 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*! \mainpage Helios Documentation v1.3.23
<p> <br> </p>
\image html AlmondVarietyReconstruction.png
<h3> <br><br>
The Helios simulation system is a versatile modeling framework that handles tasks such as managing geometry and associated data structures through a C++ API. Plug-ins build on the Helios core engine, and access the geometry and data via the Helios context. The system comes with a visualization plug-in that can produce stunning renderings of model geometry and data with relatively little effort.
</h3>
<p> <br></p>
<h1>System Requirements</h1>
Helios is compatible with Mac, Linux, and PC platforms. Some plug-ins require an <a href="www.nvidia.com">NVIDIA</a> graphics processing unit (GPU), such as the radiation model and LiDAR plug-ins.
<p> <br></p>
<h1>Downloading the Code</h1>
The code repository is located at <a href="https://www.github.com/PlantSimulationLab/Helios">https://www.github.com/PlantSimulationLab/Helios</a>. The best way to download it is using "git", which allows you to easily update your code when new updates are available.
To do so, first install git, then using your command-line interface (e.g. terminal) change into the directory where you want to download the code, then type:
~~~~~~
$ git clone https://www.github.com/PlantSimulationLab/Helios
~~~~~~
As updates are released, update your version of the code by typing:
~~~~~~
$ git pull
~~~~~~
You can always check which version you are on by typing:
~~~~~~
$ git log
~~~~~~
<p> <br><br><br><br> </p>
\image html doc/images/PSL_logo_compact.png
<p> <br><br> </p>
Financial support provided by:
\image html doc/images/sponsors.jpg
<p> <br><br> </p>
Acknowledgement of third-party software:
The Helios core engine uses all or parts of the following third-party open-sourced software libraries:
libpng:
Copyright (c) 1995-2019 The PNG Reference Library Authors.
Copyright (c) 2018-2019 Cosmin Truta.
Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
Copyright (c) 1996-1997 Andreas Dilger.
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
pugixml:
Copyright (c) 2006-2018 Arseny Kapoulkine
zlib:
Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler
Plug-ins may use other third-party software, which is acknowledged in their documentation pages.
*/
/*! \page "Overview" Overview
\tableofcontents
\section whatisAPI What is an API?
Helios is a C++ application programming interface (API) that provides libraries to help with writing programs related to 3D simulation of physical processes. This means that Helios itself is not a program that the user runs, rather it is a set of libraries that are incorporated into the program that a user writes. To read more about APIs, see <a href="https://en.wikipedia.org/wiki/Application_programming_interface">en.wikipedia.org/wiki/Application_programming_interface</a>.
The Helios API consists of many C++ <a href="https://en.wikipedia.org/wiki/C%2B%2B_classes">classes</a> and <a href="http://www.cplusplus.com/doc/tutorial/functions/">functions</a>, which are accessible within a C++ program by 1) including the appropriate header file in the program, and 2) linking to the appropriate library at build/compile time. Specific examples of how this is done are given in the \ref Tutorials and elsewhere in the documentation.
\section Prereqs C++ Prerequisites
Users need only a basic understanding of how to write and run simple C++ programs. Becoming an expert C++ programmer is not necessary to use Helios. In addition to knowing how to write a basic program in C, there are only a relatively few number of C++ constructs that the user must be familiar with. A general list of these are given below, along with links to good tutorials on how to get started.
- Programs/Namespaces: <a href="https://www.youtube.com/watch?v=SWZfFNyUsxc&list=PLAE85DE8440AA6B83&index=2">YouTube tutorial</a>, <a href="http://www.cplusplus.com/doc/tutorial/namespaces/">cplusplus.com</a>
- Functions: <a href="https://www.youtube.com/watch?v=bsWWHo4KDHE">YouTube tutorial</a>, <a href="https://www.youtube.com/watch?v=3pAWJ40I1QE&list=PL318A5EB91569E29A&index=11">YouTube tutorial</a>
- For Loops: <a href="https://www.youtube.com/watch?v=sBO8yvyyBI0&index=22&list=PLAE85DE8440AA6B83">YouTube tutorial</a>
- Arrays/Vectors: <a href="https://www.youtube.com/watch?v=1kLw8kZuccQ&list=PLAE85DE8440AA6B83&index=32">YouTube tutorial (arrays)</a>, <a href="https://www.youtube.com/watch?v=Cq1h1KPoGBU">YouTube tutorial (vectors)</a>
- Classes/Structures:<a href="https://www.youtube.com/watch?v=ABRP_5RYhqU&index=12&list=PLAE85DE8440AA6B83">YouTube tutorial</a>
- Pointers: <a href="https://www.youtube.com/watch?v=Fa6S8Pz924k&list=PLAE85DE8440AA6B83&index=38">YouTube tutorial</a>
\section PrereqsHelios Helios Prerequisites
Before beginning, you will want to familiarize yourself with Helios vector types, which are commonly used in specifying function arguments. These are C++ structures that have two or more data members. For example, a \ref vec3 type has three floating point members: x, y, z. A vec3 is commonly used to represent a Cartesian point in space. More comprehensive information on available vector types is given in Section \ref VecTypes and \ref context_vectors.
It may be useful to familiarize yourself with <a href="https://en.wikipedia.org/wiki/Spherical_coordinate_system">spherical coordinate systems</a>, which is how rotation angles are typically specified. It may also be helpful to familiarize yourself with the <a href="https://en.wikipedia.org/wiki/RGB_color_space">RGB color model</a>, which is how custom colors are specified.
\section ModelGeom Model Geometry and Data
Geometry to be modeled is represented through one or more simple geometric shapes called primitives. Available primitives are triangles, rectangles (patches) and voxels (see \ref Geom for more details). Using this set of simple geometric elements, nearly any object can be represented by combining elements.
The basic idea behind Helios is that each primitive element is associated with a set of data, and models are written that operate on this data. This geometry and associated data is what couples models. For example, if we are interested in modeling radiation, each primitive may have data associated with radiative properties such as emissivity, reflectivity, etc. The radiation model would then take that data, along with data that defines the primitive geometry (e.g., position, size), and use that to compute a radiative flux for the individual element.
\section ContextOverview The Helios Context
The Context is the primary C++ <a href="https://en.wikipedia.org/wiki/C%2B%2B_classes">class</a> in Helios that is used by every program. It contains many <a href="https://www.tutorialspoint.com/cplusplus/cpp_functions.htm">functions</a> associated with model geometry and data.
You can think of the Context as a package of data, which has many functions that allows you to interface with that data. The Context is used to add model geometry, read/write data associated with that geometry, and manage other model data such as timeseries. The Context is illustrated graphically in the figure below. In the example depicted, the Context contains three primitives - a triangle and two patches - each of which is associated with various types of data (emissivity, temperature, etc.).
\image html images/Context_sketch.png
\section PluginsOverview Model Plug-ins
The Context itself does not do any modeling. It only contains information about model geometry and data. Model plug-ins are C++ classes that operate on data contained in the Context to compute some set of values. The figure above illustrates this graphically. A model plug-in is usually given a <a href="http://www.cplusplus.com/doc/tutorial/pointers/">pointer</a> to the Context, and the model uses that pointer to access functions associated with the context. For example, a model plug-in may want to access the position of a given primitive, or the temperature associated with a primitive, which it would do by calling a Context function. Generally, a model plug-in class has several member functions that perform tasks such as setting model inputs or running the model. When a model runs, it usually creates some additional data in the Context for each primitive based on model outputs.
\section DocOverview Using the Documentation
All classes and member functions are documented, and can be searched using the search bar in the upper right-hand corner of the documentation. For example, you may come across a function where you are unsure of the order or meaning of arguments. Simply type in the name of the function in the search bar, and you will be taken to a description of the function and all argument definitions.
To continue from here, you may prefer to learn by example using the \ref Tutorials. More detailed explanations of Helios features can be found throughout the User's Guide.
*/
/*! \page "PlugIns" Plug-ins
Links to the documentation for plug-ins are given below. The documentation for plug-ins have several common elements that tell you what is needed to run them.
1. Dependencies: Any dependent packages that need to be installed before using the plug-in.
2. Build: Reference to the plug-in within the project CMakeLists.txt file.
3. Header: The relevant header file that must be included in your program to use the plug-in.
4. Class: C++ class associated with the plug-in and the class constructor(s).
5. Usage: Explanation of plug-in member functions for performing various tasks related to the plug-in. In general, these explanations will comprise the majority of the plug-in documentation.
- \subpage VisualizerDoc "Visualizer: visualization of model geometry and data"
- \subpage WeberPennDoc "Weber-Penn Tree: Procedural tree architecture generation"
- \subpage RadiationDoc "Radiation Model: GPU-accelerated ray-tracing radiation transport model"
- \subpage EnergyBalanceDoc "Energy Balance Model: Surface energy balance solution"
- \subpage BLConductanceDoc "Boundary-Layer Conductance: Perform boundary-layer conductance model calculations based on several possible models."
- \subpage LiDARDoc "LiDAR: Processing and visualizing terrestrial LiDAR data"
- \subpage AerialLiDARDoc "Aerial LiDAR: Processing and visualizing aerial LiDAR data"
- \subpage PhotosynthesisDoc "Photosynthesis Model: Photosynthetic assimilation model"
- \subpage StomatalDoc "Stomatal Conductance Model: Model for the conductance of water vapor through stomatal pores"
- \subpage SolarPositionDoc "Solar Position Model: Model for the position of the sun in the sky, as well as models of solar radiation flux and longwave flux from the sky."
- \subpage VoxelIntersectionDoc "Voxel Intersection: Determine planar primitive elements that lie within voxel primitives."
- \subpage CanopyGeneratorDoc "Canopy Generator: Simple generation of different type of plant and canopy geometries."
- \subpage PlantArchitectureDoc "Plant Architecture: Flexible procedural plant generation with dynamic growth and phenology."
*/
/*! \page DependentSoftware Install and Set-up
\tableofcontents
\htmlonly
<iframe width="560" height="315" src="https://www.youtube.com/embed/rg21UHxR16s?si=lJ7qJDKMF-Mg_WOX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
<iframe width="560" height="315" src="https://www.youtube.com/embed/pPoAfE69VcI?si=13mwnedvYq_ekuk-" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
\endhtmlonly
This page will guide you through installation and set-up of dependent software needed to build and run Helios-based programs.
\section WhichPlatform Which platform to use for Helios programming?
As Helios is simply C++ code, it can be used on any platform that supports C++ programming. If you prefer to use an interactive development environment (IDE), two great options are <a href="https://www.jetbrains.com/clion/">CLion</a> by JetBrains (recommended) and <a href="https://code.visualstudio.com">VS Code</a>. These IDEs are available on Windows, Linux, and Mac, and make setting up Helios projects relatively easy. CLion is free for educational purposes, and is loaded with very nice features for C++ development such as direct display of Helios documentation. VS Code also works, but is a little more clunky. Building and compiling from the command-line and using any text editor such as Vim or Emacs also works just fine.
\section SetupPC Set-up on Windows PC
\subsection SetupPCMSVC Install Microsoft Visual Studio C++ compiler tools
Download and install Microsoft Visual Studio Community 2022 if your GPU has compute capability of 5 or higher. You can look up your GPU's compute capability here. If your compute capability is less than 5, you'll need to download Visual Studio Community 2019 and CUDA 10.2 to ensure compatibility. The link to download older versions of Visual Studio is here: <a href="https://visualstudio.microsoft.com/vs/older-downloads/">https://visualstudio.microsoft.com/vs/older-downloads/</a>. It will require that you <a href="https://visualstudio.microsoft.com/dev-essentials/">join the free Dev Essentials program</a> in order to access the old downloads. Once you have reached the downloads page, Download Visual Studio Community 2019. For more information on choosing your compiler version, consult \ref chooseCUDA "this page".
Once you have successfully downloaded the EXE install file, you can run it to perform the installation. The important step is to be sure to install the optional packages for C++ Desktop Development. The figure below shows the check box to enable. When the installer finishes, there is no need to actually open Visual Studio, and you can move on to the next step.
\image html MSVC_cpp_options.png
\subsection SetupPCCLion Setting up basic build functionality
It is recommended for PC that you download and install the CLion IDE, found here: <a href="https://www.jetbrains.com/clion/download/#section=windows">https://www.jetbrains.com/clion/download/#section=windows</a>. Refer to the documentation page \ref CLionIDE for information on how to get a free education license.
When you open CLion, it will prompt you to open a project. You can have it automatically pull the Helios code from GitHub by clicking on the icon labeled "from VCS". By default, it should bring up Git as the default version control system. You may need to install Git, which can be done by simply clicking the button to download and install. Then, type in the URL for the Helios GitHub repository "https://www.github.com/PlantSimulationLab/Helios", select the directory where you'd like the Helios source code to be located, and hit "Clone". This should give you a fresh copy of Helios within CLion with the README file displayed.
The next step is to set up the Microsoft Visual Studio C++ compiler in CLion. It may automatically open up a new project wizard, but you can also do it yourself by going to File->Settings, then in the left pane, go to "Build, Execution, Deployment->Toolchains". With any luck, it should automatically add and detect Microsoft Visual Studio. If it doesn't, click the "+" icon and click on "Visual Studio". It may also detect and use MinGW as the default toolchain. It is recommended to remove this toolchain by clicking on it and then the '-' button.
We then want to change the "Architecture" to "x64" to build in 64-bit mode. Note that this will likely not be an option in the drop-down menu, but you can just type it in. If you do not get the green check boxes and a successful auto-detection as shown below, there is a good chance that you did not install Visual Studio correctly, and you missed the step to enable C++ tools.
\image html CLion_MSVC_setup.png
The last step is to verify the build settings by clicking on the next option down from "Toolchains" which is "CMake". Under "Toolchain" verify that it is using Visual Studio as shown below. Next, under the "Generator" drop-down choose "NMake Makefiles". If it says "default: NMake Makefiles", it is a good idea to select the dropdown and explicitly choose "NMake Makefiles" because this can sometimes be automatically changed to "Ninja" without warning. Note that prior to CLion v2021.3 there is no Generator drop-down, but it should use NMake Makefiles by default.
\image html CLion_generator_setup.png
That should be all that is needed to build basic programs that do not require CUDA. You can test by building the context\_selftest project in the "samples" directory. In the left "Project" pane (main CLion window), expand the "samples" folder, and the subdirectory called "context\_selftest". Right-click on the CMakeLists.txt file in that directory and select "Load CMake Project". You should then be able to compile and run it by clicking the play icon in the upper right hand corner of the CLion window. If you get build errors that have the word "Ninja" in various places, you missed the previous step changing the Generator to "NMake Makefiles".
\subsection SetupPCCUDA Setting up NVIDIA CUDA
The NVIDIA CUDA library is needed to build and run any plug-ins that run on the GPU. Consult this page for help choosing the right CUDA version based on your C++ compiler and GPU compute capability: \ref ChoosingCUDA.
The latest CUDA version can be downloaded here: <a href="https://developer.nvidia.com/cuda-downloads">https://developer.nvidia.com/cuda-downloads</a> (note that if you installed Visual Studio 2019 instead of 2022, you'll need to install CUDA 10.2 instead of the latest version). Download the base CUDA Toolkit installer for your Windows OS. Installing from the "exe (network)" type will result in a smaller file being downloaded. Click through the installer and accept all the default options. By default, it should have installed to 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v1X.X\', where v1X.X is the version that you installed. You can verify this installation location using the file browser.
In order to use CUDA within CLion, you need to tell it where to find the CUDA toolkit. To do this, open up the settings in CLion, and go to "Build, Execution, Deployment" and then to CMake. Click the icon next to the "Environment" field to edit environmental variables. Find the variable named "Path", and double click to edit it. At the end of the list of directories, add the path to the CUDA bin folder, i.e., 'C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v1X.X\bin;'. Make sure there is a semicolon before and after the path, and that you replace the v1X.X with your actual CUDA version. It is important to hit the return key, which should cause the Path variable list to turn blue. When you hit OK, the Path variable should be listed under the Environment field.
Once that is done, you can test it by building and running the self-test for a CUDA-based plug-in such as the energy balance model following similar steps above for the context\_selftest. If you get a CMake error that asks you to 'Specify CUDA_TOOLKIT_ROOT_DIR', it can't find your CUDA install, and most likely you set the "Path" variable incorrectly.
\subsubsection TdrDelay Increasing Timout Detection (TDR) Delay
The Windows timeout detection (TDR) mechanism can erroneously detect that the GPU has stopped responding while it is performing calculations, resulting in a "Display driver stopped responding and has recovered" error. The TDR can be disabled by following the instructions here: <a href="https://docs.nvidia.com/deploy/pdf/CUDA_TDR_delay.pdf">https://docs.nvidia.com/deploy/pdf/CUDA_TDR_delay.pdf</a>. The instructions are also given below:
1. Open the registry editor by typing "regedit" in the Windows search bar.
2. Navigate to the following registry subkey: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers.
3. If the TdrDelay key does not exist, right-click the GraphicsDrivers key, select New, and then select DWORD (32-bit) Value. Name the new value TdrDelay.
4. Double-click TdrDelay and add 600 for the Value data and make it a Decimal (instead of Hexadecimal). Click OK. If you encounter the same "Display driver stopped responding and has recovered" error in the future, increase the value.
5. Close the registry editor and restart the computer for the changes to take effect.
\subsubsection Automatically Installing Helios Dependencies
Running Helios requires several packages to be installed. To install all required packages for all plugins automatically, simply run the following shell script with the argument "ALL" (or with no arguments): `source dependencies.sh`
There are a few additional options for installing dependencies if it is not necessary to use all plugins.
To install only the dependencies required to run Helios with no plugins (or plugins that require no packages), use the argument "BASE": `source dependencies.sh BASE`
To install only the dependencies required to run Helios with the visualizer plugin, use the argument "VIS": `source dependencies.sh VIS`
To install only the dependencies required to run Helios with CUDA (required for the Radiation, Energy Balance, LiDAR, Aerial LiDAR, and Voxel Intersection plugins), use the argument "CUDA": `source dependencies.sh CUDA`
Note that this script only works for macOS and Linux operating systems. Windows users must install dependencies manually. Also note that CUDA is incompatible with macOS, and Mac users cannot run or install dependencies for the plugins that require CUDA.
\subsubsection OptiXWSL Manually installing OptiX if using Windows Subsystem for Linux (WSL)
OptiX is normally packaged with Helios, such that you do not have to worry about installing it. However, if you are using Windows Subsystem for Linux (WSL), you will need to manually install OptiX since the version included with Helios does not have the required drivers for WSL. You can follow the instructions on this site to perform the installation: <a href="https://forums.developer.nvidia.com/t/problem-running-optix-7-6-in-wsl/239355/7">https://forums.developer.nvidia.com/t/problem-running-optix-7-6-in-wsl/239355/7</a>.
Alternatively, simply run the dependencies script: `source dependencies.sh`
This will automatically install and configure the Linux drivers (version 470.256.02) to run OptiX.
\section SetupLinux Set-up on Linux
\subsection SetupLinuxCLion Setting up basic build functionality
If you are using the CLion IDE, you will at a minimum need to ensure that Git is installed on your system. Simple command-line tools are available to easily install dependent software libraries. The appropriate commands will be given in the documentation to install any required libraries. For Linux systems, the apt-get command can be used, which comes pre-installed.
Git: It is recommended to install Git in order to facilitate easy download and updating of the Helios source software. This can be accomplished via the command line "sudo apt-get install git". Note that currently CLion does not have an option to automatically install Git like on Windows or MacOS.
When you open CLion for the first time, or by going to "File->New->Project from Version Control", the default Version Control system should be Git. Type in the URL for the Helios GitHub repository: "https://www.github.com/PlantSimulationLab/Helios", select the directory where you'd like the Helios source code to be located, and hit "Clone".
If you are opening CLion for the first time, it should also open up a Toolchain Wizard window (or you can find it by going to "File->Preferences->Build, Execution, Deployment->Toolchains". It should automatically pick up Make and the C/C++ compilers if they come pre-installed on your system. If they are not auto-detected, you can install them from the Terminal command line: "sudo apt-get install cmake gcc g++".
Next, click on the "CMake" tab below Toolchains and be sure the "Generator" drop-down is set to "Unix Makefiles" and NOT Ninja or Default. You can also change the Build directory if you like, such as to simply be "build".
Once these have been installed at the system level, this is everything you will need to build basic Helios programs that do not use CUDA-based plug-ins or the Visualizer. If you are not using CLion, you can install git, cmake, gcc, and g++ from the command-line and build/compile using commands as detailed in the main Helios User Guide.
\subsection SetupLinuxCUDA Setting up NVIDIA CUDA
The NVIDIA CUDA library is needed to build and run any plug-ins that run on the GPU. While CUDA can be installed on Linux via apt-get, this tends to often cause problems. It has proven more robust to simply download CUDA from the NVIDIA website and run the installer. Consult this page for help choosing the right CUDA version based on your C++ compiler and GPU compute capability: \ref ChoosingCUDA.
Note that individual plugins may have their own library dependencies. Consult their documentation for dependency information. The latest CUDA version can be downloaded here: <a href="https://developer.nvidia.com/cuda-downloads">https://developer.nvidia.com/cuda-downloads</a>. However, you'll want to be sure that the version of CUDA that you install works with your compiler version. This website has a table showing compatibility for all versions: <a href="https://gist.github.com/ax3l/9489132">https://gist.github.com/ax3l/9489132</a>, check the g++ column. To figure out which version of g++ you have, you can type the command "g++ --version".
The Linux installation guide for the latest version of CUDA can be found here: <a href="https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html">https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html</a>. If you are installing an older version, you can find its Linux installation guide within the documentation for that specific version. Note also that Table 1 gives gcc/g++ compiler compatibility information.
Probably the easiest installation approach is to use the runfile installer type. When you choose this option on the downloads page, it will give you two commands to run the installer: 1) a 'wget' command to download the installer, 2) the command to run the downloaded installer. Complete instructions can be found in <a href="https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html#runfile">Section 7</a> of the latest Linux install guide. Note that one of the steps is disabling the Nouvou graphics drivers, which disables the "free" graphics driver that may be on your system and can conflict with the NVIDIA driver. This can be done in a few easy commands:
1. echo blacklist nouveau > /etc/modprobe.d/blacklist-nvidia-nouveau.conf
2. echo options nouveau modeset=0 >> /etc/modprobe.d/blacklist-nvidia-nouveau.conf
A restart is then needed. It is usually a good idea to install the graphics driver that comes with the CUDA installer to avoid incompatibility issues.
\subsection SetupLinuxVis Dependencies of the Visualizer Plug-in
The last set of dependent packages you are likely to encounter are related to the Visualizer plug-in. A single apt-get command is listed in the Visualizer documentation to install these dependent packages.
\section SetupMac Set-up on Mac
\subsection SetupMacCLion Setting up basic build functionality
CLion provides the ability to install all required dependent software (except for CUDA, see below) directly from the IDE. When you open CLion for the first time, or by going to "File->New->Project from Version Control", the default Version Control system should be Git, and it should prompt you to install git along with XCode. Follow the prompts to do so, but if it fails you can also install XCode from the App Store. Type in the URL for the Helios GitHub repository: 'https://www.github.com/PlantSimulationLab/Helios', select the directory where you'd like the Helios source code to be located, and hit "Clone".
If you are opening CLion for the first time, it should also open up a Toolchain Wizard window (or you can find it by going to "CLion->Preferences->Build, Execution, Deployment->Toolchains". It should automatically pick up Make and the C/C++ compilers if you have XCode installed.
Next, click on the "CMake" tab below Toolchains and be sure the "Generator" drop-down is set to "Unix Makefiles" and NOT Ninja or Default. You can also change the Build directory if you like, such as to simply be "build".
Once these have been installed at the system level, this is everything you will need to build basic Helios programs that do not use CUDA-based plug-ins or the Visualizer.
If you are not using CLion, you can install and run everything you need from the command-line. Simple command-line tools are available to easily install dependent software libraries. The appropriate commands will be given in the documentation to install any required libraries. For Mac OSX, <a href="https://brew.sh">homebrew</a> is a great package installer. Homebrew itself can be installed via a single command:
~~~~~~
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
~~~~~~
Git: It is recommended to install Git in order to facilitate easy download and updating of the Helios source software. This can be accomplished via the command line "brew install git".
CMake: Components of Helios are compiled using the CMake package (<a href="www.cmake.org">www.cmake.org</a>). Version 3.15+ is required. CMake can be easily installed via the command line using homebrew "brew install cmake".
C/C++ Compiler: You will also need a C/C++ compiler installed - we recommend using the GNU compilers or the AppleClang compilers. The GNU compilers can easily be installed via the command line "brew install gcc".
*/
/*! \page API User/API Guide
\tableofcontents
<!-- ************* BUILDING AND COMPILING ************* -->
\section BuildCompile Building and Compiling Your Own Projects
\subsection DirStruct Basic Directory Structure
Projects that use the Helios API can be located in any directory, and simply need to reference the location of the source code and plug-ins. Typically, the project directory contains the following files and directories (see 'samples' directory for examples):
<ul>
<li>'build' directory.
<li>.cpp file containing a main() routine, and other auxiliary .cpp files.</li>
<li>CMakeLists.txt file, which is used to generate a makefile (see next section).</li>
<li>.h header files (optional).</li>
</ul>
A prototypical directory structure for a project folder is given below:
<ul>
<li> build (directory) </li>
<ul>
<li> executable </li>
</ul>
<li> CMakeLists.txt </li>
<li> main.cpp </li>
</ul>
\subsection BuildDir Build Directory
It is generally convenient to have a separate directory in which the project is built. This makes it easy to start fresh with a new build, or create multiple builds on different systems. Usually, the build directory is a subdirectory within the project directory (see 'samples' directory for examples).
\subsection Source Main and auxiliary .cpp files
Projects using the Helios API must have a file containing a main() program, and can have any number of complimentary routines and files. Generally, the file containing the main program will include the Context.h header file, and declare the Context class (see Sect. \ref ContextSect below).
\subsection CMake CMakeLists.txt File
Projects that use the Helios API are typically built using the CMake package a CMakeLists.txt file. Helios requires CMake version 3.15+. A prototypical CMakeLists.txt file used for building Helios samples and projects is given in the code sample below. Inputs for the specific case are entered in the top block of code by setting variables (see the CMake 'set' command reference). The user sets the location of the Helios base directory, the name of the executable file, any source or header files, and a list of plug-ins to use (the example below uses the 'visualizer' plug-in). The last line in the file references another file in the core/ directory that contains additional code for setting up the project.
~~~~~~
# Helios standard CMakeLists.txt file version 1.9
cmake_minimum_required(VERSION 3.15)
project(helios)
#-------- USER INPUTS ---------#
#provide the path to Helios base directory, either as an absolut path or a path relative to the location of this file
set( BASE_DIRECTORY "../.." )
#define the name of the executable to be created
set( EXECUTABLE_NAME "executable" )
#provide name of source file(s) (separate multiple file names with semicolon)
set( SOURCE_FILES "main.cpp" )
#specify which plug-ins to use (separate plug-in names with semicolon)
set( PLUGINS "visualizer" )
#-------- DO NOT MODIFY ---------#
include( "${BASE_DIRECTORY}/core/CMake_project.txt" )
~~~~~~
The easiest way to compile the code is by using an IDE such as CLion, which is described in detail on the page \ref CLionIDE "Using the CLion IDE with Helios".
To build the code from the command line based on the CMakeLists.txt file, which creates a makefile, simply run the command 'cmake', followed by the path to the CMakeLists.txt file. If, as in the examples above, you are currently in the build directory and your CMakeLists.txt file is located one directory up, the CMake build is accomplished through:
~~~~~~
$ cmake ..
~~~~~~
By default, this will build Helios in "debug" mode. This is useful for debugging and testing because it will generate debug symbols and output more detailed error messages to the command line. However, this will make the code run much slower because it disables compiler optimizations (usually 3x slower on Linux and 4-5x slower on PC). For 'production' runs, it is recommended to build in 'release' mode in order to enable compiler optimizations. This is accomplished by passing an additional command-line argument to CMake:
~~~~~~
$ cmake -DCMAKE_BUILD_TYPE='Release' ..
~~~~~~
The code can then be compiled by issuing the 'make' command from the build directory, which will produce an executable in the build directory.
\subsection DirScript New Project Script
There is a script in the main Helios directory that can quickly set up a new project called "create\_project.sh". First, create a new directory where the project will exist, for example:
~~~~~~
$ mkdir projects/myProject
~~~~~~
To set up the new project, run the create\_project.sh script, with the input argument of the project directory:
~~~~~~
$ utilities/create_project.sh projects/myProjects
~~~~~~
This will create the CMakeLists.txt file, a main.cpp file template, and an empty build directory.
You can also specify plug-ins as command-line arguments to the create\_project.sh script, in which case the script will create a CMakeLists.txt and main.cpp file that are set up to load those plug-ins:
~~~~~~
$ utilities/create_project.sh projects/myProjects radiation visualizer
~~~~~~
\subsection GlobalInclude C++ Standard Library Include Files
The file global.h, which is included in the file Context.h, includes most C++ standard library header files that would be used in a typical Helios program. Thus, most commonly it is not necessary to include C++ header files in your main program files (assuming you are at least including "Context.h" or a plug-in header file).
The included header files are tabulated below.
<table>
<tr><th>Header File</th></tr>
<tr><td>\<cstdlib\></td></tr>
<tr><td>\<cstdio\></td></tr>
<tr><td>\<cstring\></td></tr>
<tr><td>\<iostream\></td></tr>
<tr><td>\<sstream\></td></tr>
<tr><td>\<fstream\></td></tr>
<tr><td>\<vector\></td></tr>
<tr><td>\<stdexcept\></td></tr>
<tr><td>\<exception\></td></tr>
<tr><td>\<cassert\></td></tr>
<tr><td>\<cmath\></td></tr>
<tr><td>\<memory\></td></tr>
<tr><td>\<cmath\></td></tr>
<tr><td>\<map\></td></tr>
<tr><td>\<algorithm\></td></tr>
<tr><td>\<ctime\></td></tr>
<tr><td>\<random\></td></tr>
<tr><td>\<chrono\></td></tr>
<tr><td>\<thread\></td></tr>
<tr><td>\<iomanip\></td></tr>
<tr><td>\<filesystem\></td></tr>
</table>
<!-- **************** CONTEXT ***************** -->
\section ContextSect Context
\htmlonly
<iframe width="560" height="315" src="https://www.youtube.com/embed/qYespfkNMNI?si=iqPILUcMZjuMvGpF" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
\endhtmlonly
The Context is a C++ class that manages data and functions associated with the Helios framework. The functions of the Context are:
<ol>
<li>Add and manage geometric objects</li>
<li>Manage data associated with geometric objects and models in general</li>
<li>Manage inputs and outputs</li>
</ol>
In simplest terms, the Context stores information associated with geometric objects (primitives) and their corresponding data.
In order to use the Context, the following header must be included:
~~~~~~{.cpp}
#include "Context.h"
~~~~~~
The context is typically created within the main function:
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
Context context;
}
~~~~~~
The Context is usually passed to plugins (see \ref Plugins), which gives them access to geometry and data.
<!-- **************** VECTOR TYPES ***************** -->
\section VecTypes Vector Types
There are several vector types commonly used by the Context and other plugins (see \ref Plugins). These are C++ structures with at least two member variables. Helios vector types are defined by including the header file:
~~~~~~{.cpp}
#include "helios_vector_types.h"
~~~~~~
Note that this header is included within the 'Context.h' header, so it is not necessary to include both.
Available vector types are detailed below. Note that these vector types are all defined under the 'helios' namespace.
<table>
<tr><th>Type</th><th>Description</th><th>Data Fields</th><th>Member Functions</th><th>Math Operators</th><th>Creation Function</th></tr>
<tr><td>\ref helios::vec2 "vec2"</td><td>2D vector of floats</td><td>\ref helios::vec2::x "x", \ref helios::vec2::y "y"</td><td>\ref helios::vec2::normalize() "normalize()", \ref helios::vec2::magnitude() "magnitude()"</td><td>* (dot product), * (mult. by scalar), /, +, -, +=, ==, !=, \<\< </td><td>\ref helios::make_vec2() "make_vec2()"</td></tr>
<tr><td>\ref helios::vec3 "vec3"</td><td>3D vector of floats</td><td>\ref helios::vec3::x "x", \ref helios::vec3::y "y", \ref helios::vec3::z "z"</td><td>\ref helios::vec3::normalize() "normalize()", \ref helios::vec3::magnitude() "magnitude()"</td><td>* (dot product), * (mult. by scalar), /, +, -, +=, ==, !=, \<\< </td><td>\ref helios::make_vec3() "make_vec3()"</td></tr>
<tr><td>\ref helios::vec4 "vec4"</td><td>4D vector of floats</td><td>\ref helios::vec4::x "x", \ref helios::vec4::y "y", \ref helios::vec4::z "z", \ref helios::vec4::w "w"</td><td>none</td><td>* (dot product), * (mult. by scalar), /, +, -, +=, ==, !=, \<\< </td><td>\ref helios::make_vec4() "make_vec4()"</td></tr>
<tr><td>\ref helios::int2 "int2"</td><td>2D vector of integers</td><td>\ref helios::int2::x "x", \ref helios::int2::y "y"</td><td>none</td><td>+, -, +=, ==, !=, \<\< </td><td>\ref helios::make_int2() "make_int2()"</td></tr>
<tr><td>\ref helios::int3 "int3"</td><td>3D vector of integers</td><td>\ref helios::int3::x "x", \ref helios::int3::y "y", \ref helios::int3::z "z"</td><td>none</td><td>+, -, +=, ==, !=, \<\< </td><td>\ref helios::make_int3() "make_int3()"</td></tr>
<tr><td>\ref helios::int4 "int4"</td><td>4D vector of integers</td><td>\ref helios::int4::x "x", \ref helios::int4::y "y", \ref helios::int4::z "z", \ref helios::int4::w "w"</td><td>none</td><td>+, -, +=, ==, !=, \<\< </td><td>\ref helios::make_int4() "make_int4()"</td></tr>
<tr><td>\ref helios::SphericalCoord "SphericalCoord"</td><td>Spherical coordinate</td><td>\ref helios::SphericalCoord::radius "radius", \ref helios::SphericalCoord::elevation "elevation", \ref helios::SphericalCoord::zenith "zenith", \ref helios::SphericalCoord::azimuth "azimuth"</td><td>none</td><td> ==, !=, \<\< </td><td>\ref helios::make_SphericalCoord() "make_SphericalCoord()"</td></tr>
<tr><td>\ref helios::RGBcolor "RGBcolor"</td><td>red-green-blue color code (values normalized to 1)</td><td>\ref helios::RGBAcolor::r "r", \ref helios::RGBAcolor::g "g", \ref helios::RGBAcolor::b "b"</td><td>\ref helios::RGBcolor::scale() "scale()"</td><td>==, !=, \<\< </td><td>\ref helios::make_RGBcolor() "make_RGBcolor()"</td></tr>
<tr><td>\ref helios::RGBAcolor "RGBAcolor"</td><td>red-green-blue-alpha color code (values normalized to 1)</td><td>\ref helios::RGBAcolor::r "r", \ref helios::RGBAcolor::g "g", \ref helios::RGBAcolor::b "b", \ref helios::RGBAcolor::a "a"</td><td>\ref helios::RGBAcolor::scale() "scale()"</td><td>==, !=, \<\< </td><td>\ref helios::make_RGBAcolor() "make_RGBAcolor()"</td></tr>
<tr><td>\ref helios::Time "Time"</td><td>Time of day</td><td>\ref helios::Time::second "second", \ref helios::Time::minute "minute", \ref helios::Time::hour "hour"</td><td>none</td><td> ==, !=, \<\< </td><td>\ref helios::make_Time() "make_Time()"</td></tr>
<tr><td>\ref helios::Date "Date"</td><td>Calendar date (MM,DD,YYYY)</td><td>\ref helios::Date::day "day", \ref helios::Date::month "month", \ref helios::Date::year "year"</td><td>\ref helios::Date::JulianDay() "JulianDay()", \ref helios::Date::incrementDay() "incrementDay()", \ref helios::Date::isLeapYear() "isLeapYear()"</td><td> ==, !=, \<\< </td><td>\ref helios::make_Date() "make_Date()"</td></tr>
</table>
Vector types can be initialized by using their 'make_*()' function. For example, 'i2=make_int2(1,2);' creates an int2 with members 'i2.x -> 1' and 'i2.y -> 2'.
\subsection RGB R-G-B(-A) color vectors
There are several predefined RGB color vectors (see \ref helios::RGBcolor "RGBcolor") that can be used, which are tabulated below:
<table>
<tr><th>Color</th><th>Code</th><th>Sample</th></tr>
<tr><td>RGB::black</td><td>(0,0,0)</td><td><div style="width:50px;height:30px;background-color:rgb(0,0,0);"></div></td></tr>
<tr><td>RGB::white</td><td>(1,1,1)</td><td><div style="width:50px;height:30px;border:1px solid rgb(75,75,75);"></div></td></tr>
<tr><td>RGB::red</td><td>(1,0,0)</td><td><div style="width:50px;height:30px;background-color:rgb(255,0,0);"></div></td></tr>
<tr><td>RGB::blue</td><td>(0,0,1)</td><td><div style="width:50px;height:30px;background-color:rgb(0,0,255);"></div></td></tr>
<tr><td>RGB::green</td><td>(0,0.6,0)</td><td><div style="width:50px;height:30px;background-color:rgb(0,127,0);"></div></td></tr>
<tr><td>RGB::cyan</td><td>(0,1,1)</td><td><div style="width:50px;height:30px;background-color:rgb(0,255,255);"></div></td></tr>
<tr><td>RGB::magenta</td><td>(1,0,1)</td><td><div style="width:50px;height:30px;background-color:rgb(255,0,255);"></div></td></tr>
<tr><td>RGB::yellow</td><td>(1,1,0)</td><td><div style="width:50px;height:30px;background-color:rgb(255,255,0);"></div></td></tr>
<tr><td>RGB::orange</td><td>(1,0.5,0)</td><td><div style="width:50px;height:30px;background-color:rgb(255,127,0);"></div></td></tr>
<tr><td>RGB::violet</td><td>(0.5,0,0.5)</td><td><div style="width:50px;height:30px;background-color:rgb(127,0,127);"></div></td></tr>
<tr><td>RGB::lime</td><td>(0,1,0)</td><td><div style="width:50px;height:30px;background-color:rgb(0,255,0);"></div></td></tr>
<tr><td>RGB::silver</td><td>(0.75,0.75,0.75)</td><td><div style="width:50px;height:30px;background-color:rgb(191,191,191);"></div></td></tr>
<tr><td>RGB::gray</td><td>(0.5,0.5,0.5)</td><td><div style="width:50px;height:30px;background-color:rgb(127,127,127);"></div></td></tr>
<tr><td>RGB::navy</td><td>(0,0,0.5)</td><td><div style="width:50px;height:30px;background-color:rgb(0,0,127);"></div></td></tr>
<tr><td>RGB::brown</td><td>(0.55,0.27,0.075)</td><td><div style="width:50px;height:30px;background-color:rgb(140,69,19);"></div></td></tr>
<tr><td>RGB::khaki</td><td>(0.94,0.92,0.55)</td><td><div style="width:50px;height:30px;background-color:rgb(240,235,140);"></div></td></tr>
<tr><td>RGB::greenyellow</td><td>(0.678,1,0.184)</td><td><div style="width:50px;height:30px;background-color:rgb(173,255,47);"></div></td></tr>
<tr><td>RGB::forestgreen</td><td>(0.133,0.545,0.133)</td><td><div style="width:50px;height:30px;background-color:rgb(34,139,34);"></div></td></tr>
<tr><td>RGB::yellowgreen</td><td>(0.6,0.8,0.2)</td><td><div style="width:50px;height:30px;background-color:rgb(153,204,51);"></div></td></tr>
<tr><td>RGB::goldenrod</td><td>(0.855,0.647,0.126)</td><td><div style="width:50px;height:30px;background-color:rgb(218,165,32);"></div></td></tr>
</table>
Note that the above colors can be directly passed to \ref helios::make_RGBAcolor() "make_RGBAcolor" to specify an alpha (transparency) value:
~~~~~~{.cpp}
RGBAcolor red_trans = make_RGBAcolor( RGB::red, 0.5 );
~~~~~~
<!-- **************** COORDINATE SYSTEM ***************** -->
\section Coord Coordinate System
Helios uses a right-handed Cartesian coordinate system. (x,y,z) coordinates are typically specified using the 'vec3' data structure (see \ref VecTypes).
Rotations are typically specified using spherical angles (see \ref VecTypes). A rotation of the elevation angle \f$\theta\f$ rotates the object about its y-axis. A rotation of the azimuthal angle \f$\varphi\f$ rotates the object clockwise about its z-axis.
When compass directions are used, +y corresponds to North, and +x corresponds East. The azimuthal angle \f$\varphi\f$ is measured clockwise from North.
\image html CoordinateSystem.jpg
\image html CompassCoord.jpeg "Coordinate system."
<!-- **************** GEOMETRY ***************** -->
\section Geom Geometry
The Helios framework is centered around geometric objects called 'primitives'. Primitive elements build up the geometry of the domain, and typically store the data that couples models. For example, each primitive may have an associated surface temperature value that is updated or used by several different models.
\subsection PrimitiveTypes Primitive Types
All primitives inherit the class '\ref helios::Primitive "Primitive"', which give them common properties and functions. The available geometric primitive types are detailed below. Each primitive type has an enumeration that can be used in the code to reference each primitive type.
<table>
<tr><th>Primitive</th><th>Description</th><th>Enumeration</th></tr>
<tr><td>\ref helios::Patch "Patch"</td><td>Rectangular polygon with coplanar vertices. A patch is specified by the (x,y,z) coordinate of its center and by the lengths of its sides in the x- and y-directions. The default orientation of a patch is horizontal (i.e., it's normal is in the +z direction).</td><td>\ref helios::PrimitiveType::PRIMITIVE\_TYPE\_PATCH "PRIMITIVE_TYPE_PATCH"</td></tr>
<tr><td>\ref helios::Triangle "Triangle"</td><td>Triangular polygon specified by its three vertices.</td><td>\ref helios::PrimitiveType::PRIMITIVE\_TYPE\_TRIANGLE "PRIMITIVE_TYPE_TRIANGLE"</td></tr>
<tr><td>\ref helios::Voxel "Voxel"</td><td>Parallelpiped or rectangular prism. A voxel is specified by the (x,y,z) coordinate of its center and by the lengths of its sides in the x-, y-, and z-directions. The default orientation of a voxel is axis-aligned.</td><td>\ref helios::PrimitiveType::PRIMITIVE\_TYPE\_VOXEL "PRIMITIVE_TYPE_VOXEL"</td></tr>
</table>
\subsection AddingPrims Adding Primitives
Primitives are referenced by their 'universal unique identifier' or UUID. When a function is called to add a primitive to the context, a UUID is returned that can be used later to reference the primitive. Objects can be formed simply by storing a group of UUIDs corresponding to the primitives that make up the object.
Each primitive type has a different function that is used to add it to the Context, which are detailed in the table below.
<table>
<tr><th>Primitive</th><th>Adder function</th></tr>
<tr><td>\ref helios::Patch "Patch"</td><td>
<ul>
<li>\ref helios::Context::addPatch(const helios::vec3 & center, const helios::vec2 & size ) "addPatch( vec3 center, vec2 size )"</li>
<li>\ref helios::Context::addPatch(const helios::vec3 & center, const helios::vec2 & size, const helios::SphericalCoord & rotation ) "addPatch( vec3 center, vec2 size, SphericalCoord rotation )"</li>
<li> \ref helios::Context::addPatch(const helios::vec3 & center, const helios::vec2 & size, const helios::SphericalCoord & rotation, const helios::RGBcolor & color ) "addPatch( vec3 center, vec2 size, SphericalCoord rotation, RGBcolor color )" </li>
<li>\ref helios::Context::addPatch(const helios::vec3 & center, const helios::vec2 & size, const helios::SphericalCoord & rotation, const char* texture_file ) "addPatch( vec3 center, vec2 size, SphericalCoord rotation, const char* texture_file )"</li>
<li>\ref helios::Context::addPatch(const helios::vec3 & center, const helios::vec2 & size, const helios::SphericalCoord & rotation, const char* texture_file, const helios::vec2 & uv_center, const helios::vec2 & uv_size ) "addPatch( vec3 center, vec2 size, SphericalCoord rotation, const char* texture_file, vec2 uv_center, vec2 uv_size )"</li>
</ul>
</td></tr>
<tr><td>\ref helios::Triangle "Triangle"</td><td>
<ul>
<li>\ref helios::Context::addTriangle( const helios::vec3 & vertex0, const helios::vec3 & vertex1, const helios::vec3 & vertex2 ) "addTriangle( vec3 vertex0, vec3 vertex1, vec3 vertex2 )"</li>
<li>\ref helios::Context::addTriangle( const helios::vec3 & vertex0, const helios::vec3 & vertex1, const helios::vec3 & vertex2, const helios::RGBcolor & color ) "addTriangle( vec3 vertex0, vec3 vertex1, vec3 vertex2, RGBcolor color )"</li>
<li>\ref helios::Context::addTriangle( const helios::vec3 & vertex0, const helios::vec3 & vertex1, const helios::vec3 & vertex2, const char* texture_file, const helios::vec2 & uv0, const helios::vec2 & uv1,const helios::vec2 & uv2 ) "addTriangle( vec3 vertex0, vec3 vertex1, vec3 vertex2, const char* texture_file, vec2 uv0, vec2 uv1, vec2 uv2 )"</li>
</ul>
</td></tr>
<tr> <td>\ref helios::Voxel "Voxel"</td><td>
<ul>
<li>\ref helios::Context::addVoxel( const helios::vec3 & center, const helios::vec3 & size ) "addVoxel( vec3 center, vec3 size )"</li>
<li>\ref helios::Context::addVoxel( const helios::vec3 & center, const helios::vec3 & size, const float & rotation ) "addVoxel( vec3 center, vec3 size, float rotation )"</li>
</ul>
</td></tr>
</table>
\subsubsection AddingPatch Adding Patches
Patches are added by specifying the (x,y,z) coordinate of its center, the lengths of its sides in the x- and y-directions, and optionally its spherical rotation (see \ref Coord) and r-g-b color. The following is an example of using the 'addPatch' function to add a simple patch:
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
Context context;
vec3 center = make_vec3(0,0,1);
vec2 size = make_vec2(1,1);
uint UUID; //universal unique identifier
UUID = context.addPatch( center, size );
}
~~~~~~
This will add the Patch shown below, with the default orientation of horizontal. (Note that the addition of the checkerboard ground and the '\ref Visualizer' plugin is needed to replicate this image, which is not shown in the example code.)
\image html images/Patch.png "Patch geometric primitive."
The patch can also be rotated by adding the optional SphericalCoord argument:
~~~~~~{.cpp}
vec3 center = make_vec3(0,0,1);
vec2 size = make_vec2(1,1);
SphericalCoord rotation = make_SphericalCoord(0.25*M_PI,0.5*M_PI);
context.addPatch( center, size, rotation );
~~~~~~
This will first rotate the patch by 0.25\f$\pi\f$ rad about the x-axis such that its normal is pointing toward the +y direction, THEN it will apply a clockwise azimuthal rotation of 0.5\f$\pi\f$ rad such that its normal is pointing in the +x direction (which will be its final orientation). Note that in order to have more control over rotations, it is recommended to use the \ref Primitive::rotate() function (see "Primitive Transformations" section below).
\subsubsection AddingTriangle Adding Triangles
Triangles are added by specifying the (x,y,z) coordinates of the triangle's three vertices, and optionally its r-g-b color. The following is an example of using the 'addTriangle()' function to add a simple triangle:
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
Context context;
vec3 v0 = make_vec3(-0.5,-0.5,1);
vec3 v1 = make_vec3(0.5,-0.5,1);
vec3 v2 = make_vec3(0,0.5,1);
uint UUID; //universal unique identifier
UUID = context.addTriangle( v0, v1, v2, RGB::red );
}
~~~~~~
This will add the Triangle shown below. (Note that the addition of the checkerboard ground and the '\ref Visualizer' plugin is needed to replicate this image, which is not shown in the example code.)
\image html images/Triangle.png "Triangle geometric primitive."
An important note for triangles is that the normal direction of the triangle follows the right-hand rule: use your right hand to connect each of the vertices in the order specified, and your thumb will point in the normal direction. This is illustrated in the figure below.
\image html images/triangle_right-hand-rule.jpeg "Right-hand rule to determine triangle normal direction based on the three vertices 0, 1, and 2."
\subsubsection AddingVoxel Adding Voxels
Voxels are added by specifying the (x,y,z) coordinate of its center, the lengths of its sides in the x-, y-, and z-directions, and optionally its spherical rotation (see \ref Coord) and r-g-b color. The following is an example of using the 'addVoxel()' function to add a simple voxel:
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
Context context;
vec3 center = make_vec3(0,0,1);
vec3 size = make_vec3(1,1,1);
uint UUID; //universal unique identifier
UUID = context.addVoxel( center, size, 0, RGB::red );
}
~~~~~~
This will add the Voxel shown below, with the default orientation of horizontal. (Note that the addition of the checkerboard ground and the 'visualizer' plugin is needed to replicate this image, which is not shown in the example code.)
\image html images/Voxel.png "Voxel geometric primitive."
The voxel can also be rotated by adding the optional SphericalCoord argument:
~~~~~~{.cpp}
vec3 center = make_vec3(0,0,1);
vec3 size = make_vec3(1,1,1);
rotation = 0.25*M_PI;
context.addVoxel( center, size, rotation, RGB::red );
~~~~~~
\subsection PrimTransform Primitive Transformations
After primitives have been added to the Context, their position, size, and orientation can be further modified through transformations.
The \ref scalePrimitive() function takes a vec3 that denotes a scaling factor to apply in each Cartesian direction (x,y,z). The \ref translatePrimitive() function moves the primitive based on values provided by a vec3 that specifies the distance to translate in the x-, y-, and z-directions.
The \ref rotatePrimitive() function rotates the primitive about an axis through an angle specified in radians. To rotate about one of the x-, y-, or z-axes, the function can be supplied a string of 'x', 'y', or 'z', respectively. The primitive can also be rotated about an arbitrary axis described by a unit vector argument. By default, the axis passes through the origin, but there is also an option to specify an arbitrary axis of rotation passing through an arbitrary origin point.
It is important to note that the order in which transformations are applied matters. Each transformation is applied based on the primitives current state. Rotating a primitive centered about the origin will cause the primitive to rotate about its own center. However, if a primitive is first translated then rotated, the primitive will be rotated about the origin (0,0,0), which does not necessarily coincide with the primitive's center if it has been translated.
The table below gives a list of primitive transformation functions, each of which take either a single UUID or a vector of UUIDs to apply the same transformation to multiple primitives.
<table>
<tr><th>Transformation</th><th>Function</th></tr>
<tr><td>Translation</td><td><ul>
<li>\ref helios::Context::translatePrimitive( uint, const helios::vec3& )</li>
<li>\ref helios::Context::translatePrimitive( const std::vector<uint>&, const helios::vec3& )</li>
</ul>
</td></tr>
<tr><td>Rotation</td><td> <ul>
<li>\ref helios::Context::rotatePrimitive( uint, float, const char* )</li>
<li>\ref helios::Context::rotatePrimitive( const std::vector<uint>&, float, const char* )</li>
<li>\ref helios::Context::rotatePrimitive( uint, float, const helios::vec3& )</li>
<li>\ref helios::Context::rotatePrimitive( const std::vector<uint> &, float, const helios::vec3& )</li>
<li>\ref helios::Context::rotatePrimitive( uint, float, const helios::vec3&, const helios::vec3& )</li>
<li>\ref helios::Context::rotatePrimitive( const std::vector<uint> &, float, const helios::vec3&, const helios::vec3& )</li>
</ul>
</td></tr>
<tr><td>Scaling</td><td> <ul>
<li>\ref helios::Context::scalePrimitive( uint, const helios::vec3& )</li>
<li>\ref helios::Context::scalePrimitive( const std::vector<uint>&, const helios::vec3& )</li>
</ul>
</td></tr>
</table>
Below is a code example of applying a transformation using a pointer to the primitive:
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
// Initialize the Context
Context context;
// Add 'Patch' primitive
vec3 center(0,0,1);
vec2 size = make_vec2(1,1);
uint UUID = context.addPatch( center, size );
// Apply translation
vec3 translation(1,0,0);
context.translatePrimitive( UUID, translation );
}
~~~~~~
\subsection PrimProps Primitive Properties
All primitives have a common set of data that can be accessed by the same set of functions, such as the primitive surface area, the primitive vertices, etc.
The table below gives a list of all available primitive property setter and getter functions. In some case, there is no setter function when it is an intrinsic property of the primitive that is not changeable.
<table>
<tr><th>Property</th><th>Setter Function</th><th>Getter Function</th></tr>
<tr><td>Primitive Type</td><td>N/A</td><td>\ref helios::Context::getPrimitiveType( uint ) const </td></tr>
<tr><td>Surface Area</td><td>N/A</td><td>\ref helios::Context::getPrimitiveArea( uint ) const</td></tr>
<tr><td>Normal Vector</td><td>N/A</td><td>\ref helios::Context::getPrimitiveNormal( uint ) const</td></tr>
<tr><td>Vertex Coordinates (x,y,z)</td><td>N/A</td><td>\ref helios::Context::getPrimitiveVertices( uint ) const</td></tr>
<tr><td>Parent Object ID</td><td>N/A</td><td>\ref helios::Context::getPrimitiveParentObjectID( uint ) const</td></tr>
<tr><td>Diffuse R-G-B color code</td><td><ul><li>\ref helios::Context::setPrimitiveColor( uint, const helios::RGBcolor& )</li><li>\ref helios::Context::setPrimitiveColor( const std::vector<uint>&, const helios::RGBcolor& )</li></ul></td><td>\ref helios::Context::getPrimitiveColor( uint ) const</td></tr>
<tr><td>Diffuse R-G-B-A color code</td><td><ul><li>\ref helios::Context::setPrimitiveColor( uint, const helios::RGBAcolor& )</li><li>\ref helios::Context::setPrimitiveColor( const std::vector<uint>&, const helios::RGBAcolor& )</li></td><td>\ref helios::Context::getPrimitiveColorRGBA( uint ) const</td></tr>
<tr><td>Affine Transformation Matrix</td><td><ul><li>\ref helios::Context::setPrimitiveTransformationMatrix( uint, float (&)[16] )</li><li>\ref helios::Context::setPrimitiveTransformationMatrix( const std::vector<uint>&, float (&)[16] )</li></ul></td><td>\ref helios::Context::getPrimitiveTransformationMatrix( uint, float (&)[16] ) const</td></tr>
</table>
Some primitives have special functions specific to that type of primitive. For example, one may want to query the length and width of a Patch. These primitive-specific functions are tabulated below. If the type of the primitive corresponding to the UUID passed to the function does not match the primitive type for that function, and error will be thrown (for example passing a Triangle UUID to the function getPatchSize()).
<table>
<tr><th>Primitive Type/Property</th><th>Getter Function</th></tr>
<tr><td>Patch Center</td><td>\ref helios::Context::getPatchCenter( uint ) const</td></tr>
<tr><td>Patch Size</td><td>\ref helios::Context::getPatchSize( uint ) const</td></tr>
<tr><td>Triangle Vertex</td><td>\ref helios::Context::getTriangleVertex( uint, uint ) const</td></tr>
<tr><td>Voxel Center</td><td>\ref helios::Context::getVoxelCenter( uint ) const</td></tr>
<tr><td>Voxel Size</td><td>\ref helios::Context::getVoxelSize( uint ) const</td></tr>
</table>
<p><br></p>
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
// Initialize the Context
Context context;
// Add 'Patch' primitive
vec3 center = make_vec3(0,0,1);
vec2 size = make_vec2(1,1);
uint UUID = context.addPatch( center, size, nullrotation, RGB::red );
// Get Patch size
vec2 SIZE = getPatchSize( UUID );
}
~~~~~~
\subsection Texture Texture Mapping
Images can be overlaid on patches and triangles through a process called <a href="https://en.wikipedia.org/wiki/Texture_mapping">texture mapping</a>. There are typically two reasons for doing this. One is simply for visualization purposes, as it easily allows for complex coloring of a surface by coloring a surface according to an image. The other is to create a more complex shape by removing a portion of the primitive surface according to the transparency channel of an image. Each of these cases are described in detail below.
\subsection TextureColor Coloring Primitives by Texture Map
Patches: To color a Patch based on an image, simply pass the path to a PNG or JPEG image to the appropriate argument of the addPatch() command. Note that the path should either be absolute, or relative to the directory where the executable will be run (typically the `build' directory).
~~~~~~{.cpp}
vec3 center = make_vec3(0,0,1);
vec2 size = make_vec2(2.5,1);
SphericalCoord rotation = make_SphericalCoord(0,0);
context.addPatch( center, size, rotation, "PSL_logo_white.png");
~~~~~~
<p> <br> </p>
\image html images/Patch_textured.png "Patch geometric primitive colored by texture map."
By default, the image is stretched to fill the entire surface of the patch. Alternatively, custom mapping coordinates can be supplied as illustrated below. Texture mapping coordinates are normalized to the dimensions of the image, such that the point (u,v)=(0,0) is in the lower left of the image, (u,v)=(1,1) is in the upper right of the image and so on.
Patches: For patches, the center and size of the box used to crop the texture are specified in (u,v) coordinates. In this example, the portion of the image inside of the red box would be mapped onto the patch, while the rest would be discarded.
\image html images/GrapeLeaf_uvpatch.jpeg "."
Triangles: For triangles, the (u,v) coordinates of the three triangle vertices are specified. For triangles, custom (u,v) coordinates must be specified when texture mapping.
\image html images/GrapeLeaf_uvtriangle.jpeg "."
\subsection TextureMask Masking Primitives by Image Transparency Channel
If the image provided for texture mapping has a transparency channel, the portion of the primitive that is transparent will automatically be removed, and the rest of the non-transparent portion of the primitive will be colored according to the image. Note that only PNG images are supported, since JPEG images do not have transparency. An example is given below.
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
// Initialize the Context
Context context;
// Add 'Patch' primitive with transparency mask
vec3 center = make_vec3(0,0,1);
vec2 size = make_vec2(1,1);
uint UUID = context.addPatch( center, size, make_SphericalCoord(0,0), "GrapeLeaf.png" );
}
~~~~~~
\image html images/AlphaMask_leaf.png "Rectangular patch masked by an image with a transparency channel."
<div style="padding:10px;background-color:#FF6666 ;line-height:1.2;">
A very important performance note when using texture-masked primitives with transparency: When a texture-masked primitive with transparency is added to the Context, the solid surface area of the primitive is calculated by determining which fraction of pixels are non-transparent. This is a computationally expensive process when the image is high resolution (e.g., millions of pixels).
If you are adding many identical primitives/objects with transparency, it is better to add it to the Context one time, then copy and translate it as many times as you need. An example of this is given in the code below.
</div>
~~~~~~{.cpp}
#include "Context.h"
using namespace helios;
int main(){
// Initialize the Context
Context context;
// Add 'Patch' primitive with transparency mask
// We will add a patch at the origin and with unit size, and copy it multiple times
vec3 center = make_vec3(0,0,0);
vec2 size = make_vec2(1,1);
uint UUID = context.addPatch( center, size, make_SphericalCoord(0,0), "GrapeLeaf.png" );
for( int i=0; i<10; i++ ){
uint UUID_copy = context.copyPrimitive(UUID);
vec3 position = make_vec3( i*3, 0, 0 );
context.translatePrimitive( position );
}
// Let's delete the original "template"
context.deletePrimitive(UUID);
}
~~~~~~
<table>
<tr><th>Property</th><th>Getter Function</th></tr>
<tr><td>Texture File Name</td><td>\ref helios::Context::getPrimitiveTextureFile( uint ) const</td></tr>
<tr><td>Size/resolution of Texture</td><td>\ref helios::Context::getPrimitiveTextureSize( uint ) const</td></tr>
<tr><td>U,V Texture Coordinates</td><td>\ref helios::Context::getPrimitiveTextureUV( uint ) const</td></tr>
<tr><td>Texture Transparency</td><td>\ref helios::Context::primitiveTextureHasTransparencyChannel( uint ) const</td></tr>
<tr><td>Texture Transparency Data</td><td>\ref helios::Context::getPrimitiveTextureTransparencyData( uint ) const</td></tr>
<tr><td>Texture Color Override</td><td>\ref helios::Context::isPrimitiveTextureColorOverridden( uint ) const</td></tr>
<tr><td>Solid Fraction</td><td>\ref helios::Context::getPrimitiveSolidFraction( uint ) const</td></tr>
</table>
\subsection Compound Compound Geometry
The Context has functions to rapidly generate various shapes, which consist of many primitives. These functions simply add the primitives needed to make the specified geometry, and return a vector of UUIDs corresponding to each of the primitives. The important distinction between these functions and those to add "Objects" (described below) is that Objects retain information about the overall 3D object such as the radius of the sphere.
Functions for adding compound geometry are listed below.
<table>
<tr>
<th>Geometry</th>
<th>Description</th>
<th>Adder function(s)</th>
<th>Example</th>
</tr>
<tr>
<td>Tile</td>
<td>Patch subdivided into uniform grid of sub-patches.</td>
<td> <ul>
<li> \ref helios::Context::addTile( const helios::vec3 ¢er, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::int2 &subdiv ) "addTile( const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv )" </li>
<li> \ref helios::Context::addTile( const helios::vec3 ¢er, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::int2 &subdiv, const helios::RGBcolor &color ) "addTile( const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const RGBcolor &color )" </li>
<li> \ref helios::Context::addTile( const helios::vec3 ¢er, const helios::vec2 &size, const helios::SphericalCoord &rotation, const helios::int2 &subdiv, const char* texturefile ) "addTile( const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation, const int2 &subdiv, const char* &texturefile )" </li>
</ul>
</td>
<td>\image html images/Tile.png </td>
</tr>
<tr>
<td>Sphere</td>
<td>Spherical object tessellated with Triangle primitives.</td>
<td> <ul>
<li> \ref helios::Context::addSphere( uint Ndivs, const helios::vec3 ¢er, float radius ) "addSphere( uint Ndivs, const vec3 ¢er, float radius )" </li>
<li> \ref helios::Context::addSphere( uint Ndivs, const helios::vec3 ¢er, float radius, const helios::RGBcolor &color ) "addSphere( uint Ndivs, const vec3 ¢er, float radius, const RGBcolor &color )" </li>
<li> \ref helios::Context::addSphere( uint Ndivs, const helios::vec3 ¢er, float radius, const char* texturefile ) "addSphere( uint Ndivs, const vec3 ¢er, float radius, const char* texturefille )" </li>
</ul>
</td>
<td>\image html images/Sphere.png </td>
</tr>
<tr>
<td>Tube</td>
<td>Cylindrical tube object tessellated with Triangle primitives. Follows a specified path and can change radius along its length.</td>
<td><ul>
<li>\ref helios::Context::addTube( uint Ndivs, const std::vector< helios::vec3 > &nodes, const std::vector< float > &radius ) "addTube( uint Ndivs, const vector<vec3> &nodes, const vector<float> &radius )"</li>
<li>\ref helios::Context::addTube( uint Ndivs, const std::vector< helios::vec3 > &nodes, const std::vector< float > &radius, const std::vector<helios::RGBcolor> &color ) "addTube( uint Ndivs, const vector<vec3> &nodes, const vector<float> &radius, const RGBcolor &color )"</li>
</ul>
</td>
<td>\image html images/Tube.png</td>
</tr>
<tr>
<td>Box</td>
<td>Rectangular prism object tessellated with Patch primitives.</td>
<td><ul>
<li> \ref helios::Context::addBox(const helios::vec3 ¢er,const helios::vec3 &size, const helios::int3 &subdiv) "addBox( const vec3 ¢er, const vec3 &size, const int3 &subdiv )" </li>
<li> \ref helios::Context::addBox(const helios::vec3 ¢er,const helios::vec3 &size, const helios::int3 &subdiv, const helios::RGBcolor &color ) "addBox( const vec3 ¢er, const vec3 &size, const int3 &subdiv, const RGBcolor &color )" </li>
<li> \ref helios::Context::addBox(const helios::vec3 ¢er,const helios::vec3 &size, const helios::int3 &subdiv, const helios::RGBcolor &color, const bool revers_normals ) "addBox( const vec3 ¢er, const vec3 &size, const int3 &subdiv, const RGBcolor &color, bool reverse_normals )" </li>
</ul>
</td>
<td>\image html images/Box.png </td>
</tr>
<tr>
<td>Disk</td>
<td>Ellipsoidal disk object tessellated with Triangle primitives.</td>
<td><ul>
<li> \ref helios::Context::addDisk( uint Ndiv, const helios::vec3 & center, const helios::vec2 & size ) "addDisk( uint Ndiv, const vec3 ¢er, const vec2 &size )" </li>
<li> \ref helios::Context::addDisk( uint Ndiv, const helios::vec3& center, const helios::vec2& size, const helios::SphericalCoord& rotation ) "addDisk( uint Ndiv, const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation )" </li>
<li> \ref helios::Context::addDisk( uint Ndiv, const helios::vec3& center, const helios::vec2& size, const helios::SphericalCoord& rotation, const helios::RGBcolor& color ) "addDisk( uint Ndiv, const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation, const RGBcolor &color )" </li>
<li> \ref helios::Context::addDisk( uint Ndiv, const helios::vec3& center, const helios::vec2& size, const helios::SphericalCoord& rotation, const helios::RGBAcolor& color ) "addDisk( uint Ndiv, helios::vec3 center, helios::vec2 size, const SphericalCoord &rotation, const RGBAcolor &color )" </li>
<li> \ref helios::Context::addDisk( uint Ndiv, const helios::vec3& center, const helios::vec2& size, const helios::SphericalCoord& rotation, const char* texture_file ) "addDisk( uint Ndiv, const vec3 ¢er, const vec2 &size, const SphericalCoord &rotation, const char* texture_file )" </li>
</ul>
</td>
<td>\image html images/Disk.png </td>
</tr>
</table>
\subsection Objects Objects
Objects are geometries consisting of many primitive elements. The critical difference between "Objects" and the compound objects described above is that Objects retain information about the overall geometry such as length, radius, etc., and have many sub-functions for manipulating them and assigning data. This is often useful when you want to know information about the overall object or want to manipulate the entire object in unison.
Functions for adding objects return a uint that serves as a unique identifier for the object, which can be used for later reference and manipulation. Functions for adding objects are listed in the table below.
<table>
<tr>
<th>Object</th>
<th>Description</th>
<th>Adder function(s)</th>
<th>Example</th>
</tr>
<tr>