#! /usr/bin/env perl
#
# Demo x22 for the PLplot PDL binding
#
# Simple vector plot example
#
# Copyright (C) 2004  Rafael Laboissiere
#
# This file is part of PLplot.
#
# PLplot is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library General Public License as published
# by the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PLplot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public License
# along with PLplot; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

# SYNC: x22c.c 1.8

use PDL;
use PDL::Graphics::PLplot;
use Math::Trig qw [pi];

use constant nx => 20;
use constant ny => 20;
use constant nr => 20;
use constant ntheta => 20;
use constant nper => 100;
use constant nlevel => 10;

# Pairs of points making the line segments used to plot the user defined
# arrow
my $arrow_x = pdl [-0.5, 0.5, 0.3, 0.5, 0.3, 0.5];
my $arrow_y = pdl [0.0, 0.0,   0.2, 0.0, -0.2, 0.0];
my $arrow2_x = pdl [-0.5, 0.3, 0.3, 0.5, 0.3, 0.3];
my $arrow2_y = pdl [0.0, 0.0,   0.2, 0.0, -0.2, 0.0];

#
# Vector plot of the circulation about the origin
#
sub circulation {

    my $dx = 1.0;
    my $dy = 1.0;

    my $nx = nx;
    my $ny = ny;

    my $xmin = -$nx/2*$dx;
    my $xmax = $nx/2*$dx;
    my $ymin = -$ny/2*$dy;
    my $ymax = $ny/2*$dy;

    my $x = ((sequence($nx)-int($nx/2)+0.5)*$dx)->dummy(1,$ny);
    my $y = ((sequence($ny)-int($ny/2)+0.5)*$dy)->dummy(0,$nx);

    # Create data - circulation around the origin.
    my $cgrid2 = plAlloc2dGrid($x, $y);
    my $u = $y;
    my $v = -$x;

    # Plot vectors with default arrows
    plenv($xmin, $xmax, $ymin, $ymax, 0, 0);
    pllab("(x)", "(y)", "#frPLplot Example 22 - circulation");
    plcol0(2);
    plvect($u,$v,0.0,\&pltr2,$cgrid2);
    plcol0(1);

}

#
# Vector plot of flow through a constricted pipe
#
sub constriction {

    my $nx = nx;
    my $ny = ny;

    my $dx = 1.0;
    my $dy = 1.0;

    my $xmin = -$nx/2*$dx;
    my $xmax = $nx/2*$dx;
    my $ymin = -$ny/2*$dy;
    my $ymax = $ny/2*$dy;

    my $x = ((sequence($nx)-int($nx/2)+0.5)*$dx)->dummy(1,$ny);
    my $y = ((sequence($ny)-int($ny/2)+0.5)*$dy)->dummy(0,$nx);
    my $cgrid2 = plAlloc2dGrid($x, $y);

    my $u;
    my $v;

    my $Q = 2.0;
    my $b = $ymax/4.0*(3-cos(pi*$x/$xmax));
    my $dbdx = $ymax/4.0*sin(pi*$x/$xmax)*$y/$b;
    $u = $Q*4*$ymax/$b;
    $v = $dbdx*$u;
    $u->where(abs($y)>=$b) .= 0;
    $v->where(abs($y)>=$b) .= 0;

    plenv($xmin, $xmax, $ymin, $ymax, 0, 0);
    pllab("(x)", "(y)", "#frPLplot Example 22 - constriction");
    plcol0(2);
    plvect($u,$v,-0.5,\&pltr2,$cgrid2);
    plcol0(1);

}


sub f2mnmx {
  $f = shift;
  my $fmin = min ($f);
  my $fmax = max ($f);
  return ($fmin, $fmax);
}

# Vector plot of the gradient of a shielded potential (see example 9)

sub potential {
  # Potential inside a conducting cylinder (or sphere) by method of images.
  # Charge 1 is placed at (d1, d1), with image charge at (d2, d2).
  # Charge 2 is placed at (d1, -d1), with image charge at (d2, -d2).
  # Also put in smoothing term at small distances.

  my $rmax = nr;

  my $eps = 2;

  my $q1 = 1;
  my $d1 = $rmax / 4;

  my $q1i = - $q1 * $rmax / $d1;
  my $d1i = $rmax * $rmax / $d1;

  my $q2 = -1;
  my $d2 = $rmax / 4;

  my $q2i = - $q2 * $rmax / $d2;
  my $d2i = $rmax * $rmax / $d2;

  my $r = (0.5 + sequence (nr))->dummy (1, ntheta);
  my $theta = (2 * pi / (ntheta - 1) *
               (0.5 + sequence (ntheta)))->dummy (0, nr);
  my $x = $r * cos ($theta);
  my $y = $r * sin ($theta);
  my $cgrid2 = plAlloc2dGrid ($x, $y);
  my $div1 = sqrt (($x - $d1) ** 2 + ($y - $d1) ** 2 + $eps * $eps);
  my $div1i = sqrt (($x - $d1i) ** 2 + ($y - $d1i) ** 2 + $eps * $eps);
  my $div2 = sqrt (($x - $d2) ** 2 + ($y + $d2) ** 2 + $eps * $eps);
  my $div2i = sqrt (($x - $d2i) ** 2 + ($y + $d2i) ** 2 + $eps * $eps);
  my $z = $q1 / $div1 + $q1i / $div1i + $q2 / $div2 + $q2i / $div2i;
  my $u = -$q1 * ($x - $d1) / ($div1**3) - $q1i * ($x - $d1i) / ($div1i ** 3)
          -$q2 * ($x - $d2) / ($div2**3) - $q2i * ($x - $d2i) / ($div2i ** 3);
  my $v = -$q1 * ($y - $d1) / ($div1**3) - $q1i * ($y - $d1i) / ($div1i ** 3)
          -$q2 * ($y + $d2) / ($div2**3) - $q2i * ($y + $d2i) / ($div2i ** 3);

  my ($xmin, $xmax) = f2mnmx ($x);
  my ($ymin, $ymax) = f2mnmx ($y);
  my ($zmin, $zmax) = f2mnmx ($z);

  plenv ($xmin, $xmax, $ymin, $ymax, 0, 0);
  pllab ("(x)", "(y)",
         "#frPLplot Example 22 - potential gradient vector plot");

  # Plot contours of the potential
  my $dz = ($zmax - $zmin) / nlevel;
  my $clevel = $zmin + (sequence (nlevel) + 0.5) * $dz;

  plcol0 (3);
  pllsty (2);
  plcont ($z, 1, nr, 1, ntheta, $clevel, \&pltr2, $cgrid2);
  pllsty (1);
  plcol0 (1);

  # Plot the vectors of the gradient of the potential
  plcol0 (2);
  plvect ($u, $v, 25.0, \&pltr2, $cgrid2);
  plcol0 (1);

  # Plot the perimeter of the cylinder
  $theta = (2 * pi / (nper - 1)) * sequence (nper);
  my $px = $rmax * cos ($theta);
  my $py = $rmax * sin ($theta);
  plline ($px , $py);

}

#--------------------------------------------------------------------------
# main
#
# Generates several simple vector plots.
#--------------------------------------------------------------------------

# Parse and process command line arguments

plParseOpts (\@ARGV, PL_PARSE_SKIP | PL_PARSE_NOPROGRAM);

# Initialize plplot

plinit ();

circulation();

# Set arrow style using arrow_x and arrow_y then
# plot using these arrows.
my $fill = 0;
plsvect($arrow_x, $arrow_y, $fill);
constriction();

# Set arrow style using arrow2_x and arrow2_y then
# plot using these filled arrows.
my $fill = 1;
plsvect($arrow2_x, $arrow2_y, $fill);
constriction();

# Example of polar plot

potential ();

plend ();

