Posts by retug (10)

Revit Rebar Bender - New and Improved

Above is my first functional C# revit add-in, making bending rebar at any angle an easy task. For those non-structural engineers, the smaller the piece of rebar, the smaller the allowable bend. Being able to quickly sketch rebar to scale with minimum bend radii is often helpful to see if a detail sketch is constructible. This add-in will bend rebar to the ACI minimum allowable bend diameter and will allow for as many points as the user desires.

How to use the add-in

To start the add-in navigate to the add-in tab, click the drop down and select your desired rebar size. Once clicked, you can now start clicking the points where you want to draw the rebar. Once you are done selecting your rebar points (3) minimum, you hit escape to have Revit create a filled region in the location where you clicked. Currently, the filled region defaults to a filled region type of "Solid Black", make sure you have this filled region in your revit project for the add-in to work. The code was written for Revit 2022, I have yet to try the code in any other version of revit.

You can find the code on my github.

Lessons Learned in C#

Given that this was my first real dive in C# and the Revit API, there were a ton of things to learn a few examples.

  • 2/12 does not equal what you think it might, you have to cast your integer 2 and integer 12 to a double as shown below


        double x = 2/12; //This actually = 0
        double x = (double)2/(double)12; // 0.16667


  • I still do not fully understand FilteredElementCollector (this class gathers revit items from my understanding). Looking at these lines of code is intimidating... The lines below gather all of the filled region types in the revit project and finds the unique ID for "Solid Black"

 // find solid fill type in our revit list
            FilteredElementCollector fillRegionTypes = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType));
            var patterns = new FilteredElementCollector(doc).OfClass(typeof(FilledRegionType)).FirstElement();
            foreach (Element elem in fillRegionTypes)
                if (elem.Name == "Solid Black")
                    patterns = elem;

  • I made a fun function that tests if user selected points are clicked in clockwise or counterclockwise manner. I was super proud of this, then found out that the Revit API has this function prebuilt into the Curveloop class. I am going to tell myself that my function is way more optimized than the curveloop method to make myself feel better.

public static double ClockWise(List<XYZ> pnts)
            double y = 0;
            for (int i = 0; i <= pnts.Count - 1; i++)
                if (i == pnts.Count - 1)
                    double x = (pnts[0].X - pnts[i].X) * (pnts[0].Y + pnts[i].Y);
                    y = (double)y + (double)x;
                    double x = (pnts[i + 1].X - pnts[i].X) * (pnts[i + 1].Y + pnts[i].Y);
                    y = (double)y + (double)x;
            bool CW_CCW = true;
            if (y <= (double)0)
                CW_CCW = false;
            return y;

Future Work

Currently this add-in will not work in any view other than a drafting view, I would like to come back to this at some point and let the code work in live view. I should have tested this earlier, I started into this task trying to alleviate the issues of the original revit rebar bender and keep this completely detail component based. 

Another item to add in the future is to load the predefined hooked ends, e.g. 90 135, 180 degree hooks. This should be pretty easy if I am thinking about this correctly, but might the necessitate the need for popup window for the user to select hook end directions and hook types

More items off the top of my head, allow for self intersection (currently breaks if the rebar loops cross), update the sloppy code up on Github (could probably be 300 lines instead of 900 lines), learn C# better. Currently I do not know how to have a function return multiple outputs like a list and int. Overall a fun project that yields a semi functional end product, I will never complain about that.

Download the code off of github and try it out, let me know if you have any comments.


Revit Addin

Making a revit addin has been a goal of mine for some time. Yesterday I finally succeeded, complete with ridiculous names, images and tasks completed.

The addin is simple and essentially useless, it assigns walls of a certain type to a workset (Github).

Learning C#

I learned C# mostly through Autodesk's tutorial on the Revit API, found here. C# is different enough from python  that it initimiated me.

A few examples:

  • Declare variable types
  • Cast variables
  • Compile your code etc.


Those familiar with C# probably know all of these items, it was fun to learn on my end coming from python. This video guided me in making the ribbon found in the user interface of revit.

You can see in the code below, if you know what a for loop is, you can piece together what these lines are doing, there are just a lot more { } everywhere:

foreach (Workset workset in worksetList)
   if (workset.Name.Contains("Concrete"))
           ConcreteWalls = workset.Id.IntegerValue;
TaskDialog.Show("Revit", ConcreteWalls.ToString());
// note we have now identified the Concrete shearwall workset

Learning C# sharp was relatively quick. My mind remembered the pains of learning python, but most of the struggles with python were due to never learning about object oriented programming. Classes, objects and everything that went along with an object oriented programming were easy enough to map from python to C#.

Learning C# taught me an important skill, the use of debugger. Why I never used this while coding in Python I will never know. Debuggers allow you to not have to print variables out all the time and appear to have a lot more power that I have not yet unleashed. In the code example above, I was able to watch the debugger stepping through the foreach loop for each workset in the project, and if the workset contains "Concrete" it steps out of the for loop. I look forward to learning more about debugging in both C# and python.

As with any new skill or programming language, intimidation and coding tutorials are the obstacles to progress. Once I actually started coding, debugging, and yes, print screening still, making the addin started to click. 

A negative of C#

To debug the program you have to start and close revit all the time, this is super time consuming! The ability to quickly whip up a revit idea in dynamo and python is really unparalleled. Getting instant feed back on the items in a list of variable is definitely valuable. If you know of a way to get around revit having to fire up each time a change is made to the code, please let me know.

C# Moving forward

C# appears powerful, but will only be reserved for projects that warrant the slow development process. One that comes to my mind is the revit rebar bender. Knowing C# will help me alleviate the limitations that the rebar adaptive component faced. C# is also supported by the ETABs API and I believe you can even have your very own button in the UI of ETABs like Revit. More work in the future...

Time Histories to Response Spectrums

I have inherited an awesome project through the most unfortunate circumstances, the loss of a great engineer moving onto bigger and brighter pastures.

The project is going to be an ASCE 41 non-linear dynamic analysis and has had geotech engineers involved in picking out ground motion that represent similar ground motions that the faults near this building may produce.

Converting from time history to response spectrum can be done in ETABs, but post processing the data is kinda difficult, I can't seem to find a way to programmatically access the response spectrum curves that ETABs produces.

It's also never a bad day when you have to break out the Chopra Book, so I decided to try to code the process.

The Results


You can find the code to make plots like these  on my github:
The required data format is a .txt file that is separated with returns and tabs. I have heard not all geotechs provide their time history data in this manner, so if you want to use this, you may have to edit.

Starting into this, I thought this process involved using fourier transforms to transition from the time domain to the frequency domain, I clearly had forgotten my structural dynamics. Reading chapter 5 of Chopra and getting some guidance from fellow engineer Bryant, I was able to recreate the Newmark method outlined in the Chopra book. Adding a whole bunch of for loops later, some awesome plots popped out.

Comparing the BSE-2E plots (the big, rare earthquakes in ASCE 41) to the code generated response spectrum yielded a ~1.3 increase in peak accelerations at the typical plateau of the response spectrum (time histories were produced high accelerations). 

The BSE-1E time history plots were much closer to the code generated BSE-1E response spectrum.

Diaphragm Slicer - ETABs API

The Tool

One feature that I like to use in ETABs is the section cut tool, but it is quite cumbersome to utilize in practice:

Notice how you have to enter (4) valid points to define a section cut... a time consuming process. I love to use this tool to analyze my diaphragm forces, but you are only left with snapshots of your total diaphragm moment and shear. Defining lots of these section cuts along the length of a diaphragm is tedious.

This tool allows structural engineers to select their diaphragm in ETABs, define the slicing direction and define the number of sections to generate, plotting shear and moment at each section cut. It yields awesome plots like the following that you can use to determine diaphragm shear force and moments. The example shown below is that of a (3) sided diaphragm, 40ft long, with a 1kip/ft load applied to edge of the diaphragm.

Diaphragm Shear - Total Shear at shear wall is 40 kips

Diaphragm Moment

The shear graph above makes sense 1 kip/ft * 40ft = 40 kips to be resisted by singular shear wall in the line of the applied force; while on the other hand, the moment in the diaphragm is a little counter intuitive. This graph will make me revisit my other three sided diaphragm post at a later date.

The Goods

You can find the code to make this happen on my github as well as the sample ETABs model utilized to generate all of the plots. The code is written in python and utilizes the ETABs API to do the leg work.

A big thanks to CSI for making this possible in ETABs v19 and above. The new API of ETABs allows engineers to programmatically access any of the available tables in the interactive database. This bit of code makes the section cuts for the diaphragm:

def make_quad_etabs(name_sect,point):
    name = str(name_sect)
    final = []
    for i in range(4):
        if i == 0:
            test = [name, 'Quads', 'All', 'Analysis', 'Default', '', '', '', '0','0','0','','Top or Right or Positive3','1', '1', '1', str(point[0][0]), str(point[0][1]), str(point[0][2]), '1']
        elif i == 1:
            test = [name, '', '','', '', '', '', '', '','','','','','', '1', '2', str(point[1][0]), str(point[1][1]), str(point[1][2]), '']
        elif i == 2:
            test = [name, '', '','', '', '', '', '', '','','','','','', '1', '3', str(point[2][0]), str(point[2][1]), str(point[2][2]), '']
        elif i == 3:
            test = [name, '', '','', '', '', '', '', '','','','','','', '1', '4', str(point[3][0]), str(point[3][1]), str(point[3][2]), '']
    return final

etabs_data_sect = []
for i,(etabs_quad,sec_name) in enumerate(zip(global_quad,name)):
    etabs_data_sect.append(make_quad_etabs(sec_name, etabs_quad))

flat_etabs_data = []
for point in etabs_data_sect:
    temp = []
    for data in point:
        for sing_data in data:
mega_data = []
for point in flat_etabs_data:
    for ind_pnt in point:

TableKey = 'Section Cut Definitions'
TableVersion = 1
FieldsKeysIncluded = ['Name', 'Defined By', 'Group','Result Type', 'Result Location', 'Location X', 'Location Y', 'Location Z', 'Rotation About Z','Rotation About Y', 'Rotation About X', 'Axis Angle', 'Element Side', 'Number of Quads', 'Quad Number', 'Point Number', 'Quad X', 'Quad Y', 'Quad Z', 'GUID']
NumberRecords = len(flat_etabs_data)

y = SapModel.DatabaseTables.SetTableForEditingArray(TableKey, TableVersion, FieldsKeysIncluded, NumberRecords,mega_data)              

FillImport = True
z= SapModel.DatabaseTables.ApplyEditedTables(FillImport)
model_has_run = SapModel.Analyze.RunAnalysis()

To use the code, select your floor and change any of the input that I have noted with the #UI note in the python code. 

Typical user input includes:

  • Selecting the diaphragm you want to slice up, this is done in the ETABs model
  • Select the vector direction you want to your diaphragm to be sliced up, (1,1,0) for example is going up and to the right at a 45 degree angle, in the example below, (1,0,0) tells the program to create vertical slices along the length of the diaphragm, moving from left to right.
    • #UI
      vector = [1,0,0]
  • Define the number of slices you want to make
    • # UI Number of slices to make along the diahragm
      n_cuts = 100
  • Set the hieght, in feet, that your diaphragm exists at in ETABs
    • #UI
      height = 10 
  • Set the starting location of you diaphragm
    • #UI
  • Hit the run button on your favorite IDE

After hitting run, the program will generate the number of section cuts you told it to create and matplotlib is utilized to plot the results.

In my example code, I had the program generate 100 cuts, the 100th cut corresponds to the section cut 0099 noted below.

A nice plot is generated at the beginning as well so you can see how you are slicing your diaphragm to make sure you made your user input correctly. The red dots below correspond to where your diaphragm exists, while the blue lines corresponds to your section cuts.

Overall the tool works well and I look forward to using it on more complicated diaphragms. Test it out and let me know what you think!

Website Quality of Life Updates

The website has three updates

  1. New (hopefully easier to view) layout
  2. Slugified URLs
  3. Images that enlarge on click

1 - New (hopefully easier to view) layout

This one was by far the hardest for me to achieve, but hopefully makes the site easier to read on mobile. I have very little frontend development skills at this point and this work was 99% in reworking the html code for the website... and it was a bear for me.

The old website appeared like the image below, lots of wasted space for the stupid image to take up, it looked exceptionally bad on mobile where screen space is at a premium:


The new site has the appearance you are looking at, hopefully much better, no more wasted space:

The code changes to make this happen are subtle and I struggled with them. I still do not fully understand the <div> tag and how and why it works.

    <article class="media content-section">
      <div class="container">
        <div class="media-body">
          <div class="article-metadata">
            <img class="rounded article-img" style = "float:right" src= "{{ }}">
            <a class="mr-2" href="{% url 'user-posts' %}">{{ }}</a>
            <small class="text-muted">{{ object.date_posted|date:"F d, Y" }}</small>
            <h2 class="article-title">{{ object.title }}</h2>
            {% if == user %}
                <a class = "btn btn-secondary btn-sm mt-1 mb-1" href = "{{post.get_absolute_url}}/update">Update</a>
                <a class = "btn btn-danger btn-sm mt-1 mb-1" href = "{{post.get_absolute_url}}/delete">Delete</a>
            {% endif %}    

This post has made me identify another upgrade I need to make, a way to format code to make it look readable... more work for a later time.

2 -Slugified URLs

I thought this one was going to be difficult but it turned out to be much easier than I had anticipated. I had to make a change to my file (essentially the database which allows this blog site to work) which always scares me because the last time I did this, I lost the whole website. This time it worked and I did not have to restore the website, horray!

The term slugify is apparently a django term for turning urls into human readable urls. For example, the previous url for this post would have been, the slugified post now incorporates the post title, Without slugifying the title, the url would have been

This apparently helps with search engine optimization and will make the urls a little more meaningful.

The code to make this happen:

class Post(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField(null=True, blank=True, unique=True)

    def get_absolute_url(self):
        #return reverse('post-detail', kwargs = {'pk':})
        return reverse('post-detail', kwargs = {'pk':, 'slug': self.slug})

urlpatterns = [
    path('post/<slug:slug>/<int:pk>', PostDetailView.as_view(), name='post-detail'),

In addition to these updates, a lot of the html hyperlinks had to be updated... one example:


                <a class = "btn btn-secondary btn-sm mt-1 mb-1" href = "{{post.get_absolute_url}}/update">Update</a>


3 - Images that enlarge on click

The simplest of the three to solve. I use CKEditor for my image uploading and viewing and they have nice option to embed a link in an image. Try clicking on the image below and it should enlarge.

This solves my problem of tiny images not being readable.

1 2 Next Last

Our Sidebar

You can put any information here you'd like.

  • Latest Posts
  • Announcements
  • Calendars
  • etc