# Chemical process flow sheets TikZ/PGF

I'm working with simulation and control of chemical process-systems and I'm trying to get a grip on how to make nice looking process flow sheets. On the web everybody is referring to Microsoft Visio, but I'm on a mac and I would like to make my flowsheets slightly more flexible when it comes to using different platforms. Ideally, I would like to use TikZ/PGF or similar.

Q1: Is there a TikZ library, for Chemical Engineering, similar to that of MS Visio?

Q2: Could one generate a diagram as presented below with TikZ? (...)

Q3: ... and make it easy to reproduce, i.e. start building your own library?

EDIT: Q4: How can one generate the picture? I have a problem with the repeating and rotating structures, e.g. the valves. I would prefer if I could be able to do something like this (beware pseudo code. I have no idea how I could implement this in tikz)

\documentclass{standalone}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}

def node makeValve(<relative position>)    % generates the entire valve structure as one node
def node makeCSTR(<relative position>)     % generates the entire reactor (Mr in the picture) as one node

\node[] (feedFlow) ;
\draw[->] (feedFlow)--(\makeValve(2,0))--(\makeCSTR(1,0)) ;

\end{tikzpicture}
\end{document}


• Questions 2 and 3 are easy: Yes. :-) Also, I noticed that you have not voted on a question or answer even once. Please consider at least voting on answers to your questions that you find useful. And perhaps see http://meta.tex.stackexchange.com/questions/12/vote-early-and-often. – Peter Grill Oct 18 '12 at 7:24
• Reformulating the post... – Holene Oct 18 '12 at 8:35
• On this site, a question should typically revolve around an abstract issue (e.g. "How do I get a double horizontal line in a table?") rather than a concrete application (e.g. "How do I make this table?"). Questions that look like "Please do this complicated thing for me" tend to get closed because they are "too localized". Please try to make your question clear and simple by giving a minimal working example (MWE): you'll stand a greater chance of getting help. – hpesoj626 Oct 18 '12 at 8:48

Even after 5 years it still seems that there isn't a ready out of the box solution. So I decided to create my own. It's based on the TikZ circuit library and it allows the creation of new type of circuit diagram, based on the symbols and rules as described in the norm ISO 14617. I tried to keep the same structure and conventions as the 'circuit ee' library. At the current time it's still in the early development stages, and subject to regular changes. My goal is to create a package for CTAN. It is hosted on Gitlab as PIDcircuitTikz.

The following file show the currently implemented symbols: example.pdf The manual can be found at: PIDcircuitTikZ.pdf

Example given below. The files pgflibraryshapes.gates.pid.ISO14617.code.tex, pgflibraryshapes.gates.pid.code.tex, tikzlibrarycircuits.pid.ISO14617.code.tex, tikzlibrarycircuits.pid.code.tex and draftdrawing.cls need to be installed in the same folder as the example.

\documentclass[a4paper, landscape, border=5mm, linewidth=0.25mm, linewidthborder=0.5mm]{draftdrawing}

\usetikzlibrary{calc}

\begin{document}

\title{Simple diagram}
\designedby{Jelle Spijker}
\checkedby{}
\approvedby{}
\draftnumber{A001}
\revision{A}
\remarks{some short remarks}
\logo{logo.png}
\scale{1:1}
\unit{mm}
\draftdate{\today}

\begin{tikzdraft}[every info/.style={font=\tiny}, node distance=2]
\node[fan={name=F1,info=$$F_{1}$$}, rotate=180] at (-7,5) {};
\node[damper={name=D1,info=above left:$$D_{1}$$, adjustable}, right=of F1] {};
\node[tank={info=$$S_{1}$$, name=S1, with={bag filter element}{-0.25}{0}{rotate=90}}, below=of F1] {};
\node[regenerative pre-heater={name=H1, info=$$H_{1}$$}, anchor=input in] at ($(D1)+(1.5,0)$) {};
\node[branch={name=B1}] at (D1 |- S1) {};
\node[damper={name=D2,info'=above left:$$D_{2}$$}, adjustable] at ($(B1)+(0.75,0)$) {};
\node[tank={info=$$S_{2}$$, name=S2, with={filter element}{0}{0}{rotate=90}}] at ($(H1.output in)+(1.5,0)$) {};
\node[measurement point={name=M1}] at (D2 -| S2) {};
\node[branch={name=B2}] at ($(M1)-(0.75,0)$) {};
\node[straight tube heat exchanger={name=H2, info=$$H_{2}$$}, anchor=input] at ($(M1)+(0.75,0)$) {};
\node[tank={name=W1, info=$$W_{1}$$, with={spray nozzle}{0}{-0.5}{rotate=180}}] at ($(H2.output)+(1.5,0)$) {};
\node[measurement point={name=M2}] at ($(W1)+(0.75,0)$) {};
\node[tank={name=H3, info=above right:$$H_{3}$$, with={heating coil}{0}{0}}] at ($(M2)+(1,0)$) {};
\node[three way valve={globe, name=V1, info=below left:$$V_{1}$$, rotate=270}] at ($(H3-heating coil.south)-(0,1)$) {};
\node[fan={name=F2,info'=$$F_{2}$$}] at ($(H3)+(5,0)$) {};
\node[measurement point={name=M3}] at ($(F2)+(0.75,0)$) {};
\node[branch={name=B3}] at ($(W1.south |- V1)-(0.25,0)$) {};
\node[boiler={name=H4, info=$$H_{4}$$,with={fired type}{0}{-0.5}}] at ($(V1)-(-1,1.5)$) {};
\node[pump={displacement, name=P1, info=$$P_{1}$$, rotate=180}] at ($(H4.output)+(1,0)$) {};
\node[tank={name=T1, with={heating coil}{0}{0}, with={measurement point}{0.75}{0.75}, info=below:$$T_{1}$$}] at ($(P1)+(1.5,0)$) {};
\node[valve={name=V3, info'=$$V_{3}$$}] at (T1 -| F2) {};
\node[branch={name=B4}] at (V1 |- H4.input) {};
\node[angled valve={globe, safety function, name=V2, info=left:$$V_{2}$$}] at (B4 -| M2) {};
\node[spring={info=$$p>\SI{10}{\bar}$$}, at={V2.center}{0.5}] {};

\node[reference={name=TO1, info=right:{to aula}}] at ($(M3)+(1,0)$) {};
\node[reference={name=TO2, rotate=180, info=left:{from aula}}] at (S2 -| TO1) {};
\node[reference={name=TO3, info=left:{from outside}}, left=of S1] {};
\node[reference={name=TO4, rotate=90, info=right:{to outside}}] at ($(TO3 |- F1)+(0,1.5)$) {};
\node[reference={name=TO5, rotate=-90, info=right:{to atm}}] at ($(V2)-(0,1.5)$) {};
\node[reference={name=TO6, rotate=-90, info=right:{to water}}] at (TO5 -| B3) {};
\node[reference={name=TO7, rotate=180, info=left:{from water}}] at (V3 -| TO1) {};

\draw (H1.input in) to [flow direction] (D1);
\draw (D1) to [flow direction] (F1);
\draw (D1) to [flow direction] (B1);
\draw (S1) to [flow direction] (B1);
\draw (B1) to (D2);
\draw (D2) to [flow direction] (\currentcoordinate |- H1.input out) to (H1.input out);
\draw (S2) to [flow direction] (H1.output in);
\draw (D2) to [flow direction] (B2);
\draw (B2) to (M1);
\draw (H1.output out) to (H1.output out -| B2) to [flow direction] (B2);
\draw (M1) to (H2.input);
\draw (H2.output) to [flow direction] (W1);
\draw (W1.south -| B3) to (B3);
\draw (H2.south) to ++ (0,-0.5) to [flow direction] (B3) to [flow direction=near end] (TO6);
\draw (W1) to (M2) to (H3);
\draw (V1) to (H3-heating coil.south);
\draw (V1) to [flow direction] (V1 -| W1-spray nozzle) to (W1-spray nozzle);
\draw (H3) to [flow direction] (F2);
\draw (F2) to (M3);
\draw (H4.input) to (B4) to [flow direction] (V1);
\draw (B4) to (V2) to [flow direction] (TO5);
\draw (H3-heating coil) to (H3-heating coil |- H2.refrigerant out) to [flow direction] (\currentcoordinate -| T1-heating coil) to ($(\currentcoordinate |- F2)+(0,0.125)$);
\draw (T1-heating coil) to [flow direction'] ($(\currentcoordinate |- F2)-(0,0.125)$);
\draw (TO7) [flow direction] to (V3) to (T1) to [measurement point={name=M4}] (P1) to [measurement point={name=M5}] (H4.output);
\draw (M3) to (TO1);
\draw (TO2) to [flow direction] (S2);
\draw (TO3) to [flow direction] (S1);
\draw (F1) to [flow direction] (F1 -| TO4) to (TO4);

\node[measurement device={central control room, name=MD1}, measure=PT, at={M1.north}{}] {};
\node[measurement device={central control room, name=MD2}, measure=MT, anchor=west] at (MD1.east) {};
\node[measurement device={central control room, name=MD3}, measure=TT, at={M2.north}{}] {};
\node[measurement device={central control room, name=MD4}, measure=MT, anchor=west] at (MD3.east) {};
\node[measurement device={central control room,  name=MD5}, measure=FT, at={M3.north}{}] {};
\node[measurement device={name=MD6}, measure=LS, at={V3.center}{1.5}] {};
\node[measurement device={local control room, name=MD7}, measure=PT, at={M4}{1.6}] {};
\node[measurement device={local control room, name=MD8}, measure=TT, anchor=west]  at (MD7.east) {};
\node[measurement device={local control room, name=MD9}, measure=PT, at={M5}{1.6}] {};
\node[measurement device={local control room, name=MD10}, measure=TT, anchor=west] at (MD9.east) {};

\node[automatic operation, at={D1.north}{}] {\tiny M};
\node[automatic operation, at={D2.south}{3}{rotate around=180:(D2.south), rotate=180}]  {\tiny M};
\node[automatic operation, at={V1.center}{}{rotate around=270:(V1.center)}] {\tiny M};
\node[automatic operation, at={P1.south}{0.15}] {};
\node[automatic operation, at={F1.south}{}] {};
\node[automatic operation, at={F2}{}] {};

\draw[dashed] (MD6) to [flow direction'] (MD6 -| T1-measurement point) to (T1-measurement point);

\end{tikzdraft}
\end{document}


Note: The Tikz library can also be used without the draftdrawing.cls, which only purpose is to create a drafting sheet.

Help, tips and contributions are greatly appreciated.

• can you paste the code in your answer by editing so that people can try it? – percusse Jan 17 '18 at 21:35
• I could do that, but it are 4 files with a total of roughly 700 lines of code. I think it is better to check out the github repo. – Jelle Spijker Jan 17 '18 at 23:24
• The files pgflibraryshapes.gates.pid.ISO14617.code.tex, pgflibraryshapes.gates.pid.code.tex, tikzlibrarycircuits.pid.ISO14617.code.tex and tikzlibrarycircuits.pid.code.tex contain the actual code, whilst example.tex contain the code a user would enter, see picture in my previous answer. – Jelle Spijker Jan 17 '18 at 23:30
• I mean the code that you have pasted as a figure here. Also the link is not to GitHub – percusse Jan 18 '18 at 0:33
• @JelleSpijker Very nice start of a "chemical engineering" package, thanks! – user49901 Jan 22 '18 at 15:49

I came across this looking for something else http://www.texample.net/tikz/examples/area/electrical-engineering/

Edit: Code for a Tikz valve is available from a link at http://old.nabble.com/Overflow-when-designing-a-shape-to31589669.html#a31589669 but from the webpage it seems the author had some problems with this, so some work may be required.

You may be able to modify some of the basic elements of these flow chart like diagrams without too much trouble.

• Nice! It looks like I'll have to step my TikZ-game up to be able to do anything with the valve tikz code. But hopefully I'll be able to apply it! – Holene Oct 24 '12 at 6:56
• It seems that the second link there has died, would you happen to gave a similar link? – Taylor Scott Nov 19 '18 at 6:50

I have the same problem, here is my partial solution for a flowsheet that I need to reproduce. I know it's completely unfinished, but I hope this will help you. It only has 2 equipments and doesn't has any control loop or valve, but as you can see in the code, the images are loaded as external file so you can add more. I also know that you can draw a circle with tikz but I'm a newbie and I want to make it as simple as I can. Feel free to change anything.

\documentclass{standalone}

\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{intersections}
\usepackage{tkz-euclide}
\usetkzobj{all}
%with these two packages you can write accents and similar directly
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\begin{document}

\begin{tikzpicture}
\node[inner sep=0pt] (Absorbedor) at (0,0)
{\includegraphics[width=.1\textwidth]{filled_tower.png}};
\node[inner sep=0pt] (Flash) at (5,-6)
{\includegraphics[width=.1\textwidth]{unfilled_tower.png}};
\node[inner sep=0pt] (Divisor) at (5,-10)
{\includegraphics[width=.1\textwidth]{circle.png}};
\node[left] at (Absorbedor.west) {Absorbedor};

\draw[->,very thick, name path=line 1] (Absorbedor.south) |- (Flash.west);
\draw[->,very thick] (Flash.south) -- (Divisor.north);
\draw[-,very thick] (Divisor.west) -- (3,-10);
\draw[->,name path=line 2, opacity=0] (3,-10) |- (Absorbedor.east);         %this line is going to be replaced

% find intersection of first and second line
\path [name intersections={of = line 1 and line 2}];
\coordinate (S)  at (intersection-1);

% path a circle around this intersection for the arc

% find intersections of second line and circle
\path [name intersections={of = circle and line 2}];
\coordinate (I1)  at (intersection-1);
\coordinate (I2)  at (intersection-2);

% draw normal line segments
\draw[very thick] (3, -10) -- (I2);
\draw[->,  very thick] (I1) |- (Absorbedor.east);

% draw arc at intersection
\tkzDrawArc[color=black, very thick](S,I1)(I2);

\draw[->,very thick] (-2,-2.55) node[align=right, left] {Alimentación\\$CO_2$\\$H_2S$\\I} -- ($(Absorbedor.south west)+(0,13mm)$) node[midway, above] {1};

\draw[<-,very thick] (-2,4) node[align=right, left] {$CO_2$\\I} -| ($(Absorbedor.north west)+(0.3,-0.9 mm)$) node[near start, above] {2};

\end{tikzpicture}

\end{document}


More or less two years ago, I ran into the same issue: need to draw chemical process flow diagrams and no LaTeX tools to do it. Like Jelle Spijker did, I ended up writing my own TikZ extension. Though the serious development started about half a year ago, I was not able to go public until this week, but now the package is available on CTAN. The ones who are interested in chemical flowsheeting in LaTeX may want to have a look to the chemplants package: https://ctan.org/pkg/chemplants

• Welcome to tex.sx. – barbara beeton Nov 21 '19 at 20:48
• YES! A "few" years late for my part, but still – that's great work! 👏 – Holene Nov 23 '19 at 9:03