10.7 Drawing Complex Vector Fields

We now put our arrows to good use drawing complex vector fields. These vector fields give a representation of complex-valued functions of complex variables. Consider a Cartesian coordinate grid of points (x,y) in the plane, and some complex-valued function f defined on this grid. At every point on this grid, compute the value of f(x+iy) and call it z. Since z has both a real and imaginary value for a given (x,y) grid point, there are four dimensions to plot. What do we do? We represent the values of z by arrows planted at each grid point. Each arrow represents the value of z in polar coordinates (r,θ). The length of the arrow is proportional to r. Its direction is given by θ.

The code for drawing vector fields is in the file vectors.input. We discuss its contents from top to bottom.

Before showing you the code, we have two small matters to take care of. First, what if the function has large spikes, say, ones that go off to infinity? We define a variable clipValue for this purpose. When r exceeds the value of clipValue, then the value of clipValue is used instead of that for r. For convenience, we define a function clipFun(x) which uses clipValue to clip the value of x.

clipValue : DFLOAT := 6                          Maximum value allowed
clipFun(x) == min(max(x,-clipValue),clipValue)

Notice that we identify clipValue as a small float but do not declare the type of the function clipFun. As it turns out, clipFun is called with a small float value. This declaration ensures that clipFun never does a conversion when it is called.

The second matter concerns the possible poles of a function, the actual points where the spikes have infinite values. FriCAS uses normal DoubleFloat arithmetic which does not directly handle infinite values. If your function has poles, you must adjust your step size to avoid landing directly on them (FriCAS calls error when asked to divide a value by 0, for example).

We set the variables realSteps and imagSteps to hold the number of steps taken in the real and imaginary directions, respectively. Most examples will have ranges centered around the origin. To avoid a pole at the origin, the number of points is taken to be odd.

realSteps: INT := 25      Number of real steps
imagSteps: INT := 25      Number of imaginary steps
)read arrows

Now define the function drawComplexVectorField to draw the arrows. It is good practice to declare the type of the main function in the file. This one declaration is usually sufficient to ensure that other lower-level functions are compiled with the correct types.

C := Complex DoubleFloat
S := Segment DoubleFloat
drawComplexVectorField: (C -> C, S, S) -> VIEW3D

The first argument is a function mapping complex small floats into complex small floats. The second and third arguments give the range of real and imaginary values as segments like a..b. The result is a three-dimensional viewport. Here is the full function definition:

drawComplexVectorField(f, realRange,imagRange) ==
  delReal := (hi(realRange)-lo(realRange))/realSteps The real step size

  delImag := (hi(imagRange)-lo(imagRange))/imagSteps The imaginary step size

  sp := createThreeSpace()                           Create empty space $sp$

  real := lo(realRange)                              The initial real value

  for i in 1..realSteps+1 repeat                     Begin real iteration

    imag := lo(imagRange)                            initial imaginary value

    for j in 1..imagSteps+1 repeat                   Begin imaginary iteration

      z := f complex(real,imag)                      value of $f$ at the point

      arg := argument z                              direction of the arrow

      len := clipFun sqrt norm z                     length of the arrow

      p1 :=  point [real, imag, 0.0@DFLOAT, arg]     base point of the arrow

      scaleLen := delReal * len                      scaled length of the arrow

      p2 := point [p1.1 + scaleLen*cos(arg),         tip point of the arrow
             p1.2 + scaleLen*sin(arg),0.0@DFLOAT, arg] arrow := makeArrow(p1, p2)                     Create the arrow

      for a in arrow repeat curve(sp, a)             Add arrow to space $sp$

      imag := imag + delImag                         The next imaginary value

    real := real + delReal                           The next real value
makeViewport3D(sp, “Complex Vector Field”)         Draw it

As a first example, let us draw f(z)==sin(z). There is no need to create a user function: just pass the sinsinComplex DoubleFloat from Complex DoubleFloat.

Read the file.

)read vectors

Draw the complex vector field of sin(x).