windcrazy86 has asked for the wisdom of the Perl Monks concerning the following question:

Dear all, I am tring to calculate the angle between water diplole moments and the normal vector of a surface, the problem of "Undefined subroutine &main::Normalize called at -e line 74." appeared when I trying to get the unit vector of the dipole moment (my $direction=Normalize($dipoleMoment);). Following is the code.

#!perl use strict; use MaterialsScript qw(:all); use Math::Trig; my $doc = $Documents{"Layerhalf.xtd"}; my $setA = "Si"; my $setB = "wat"; # get the trajectory data my $trj = $doc->Trajectory; my $numFrames = $trj->NumFrames; # create a study table for the results my $std = Documents->New($doc->Name.".std"); $std->ColumnHeading(0) = "Angle (deg)"; $std->ColumnHeading(1) = "Distance (angstrom)"; my $setMolecules = $doc->UnitCell->Sets($setB)->Molecules; # run over all frames in the trajectory my $irow = 0; my $setAtoms = $doc->UnitCell->Sets($setA)->Atoms; my $plane = $doc->UnitCell->CreateBestFitPlane($setAtoms); my $bestFitPlane = $plane->BestFitPlane; for(my $frame = 201; $frame <= 300; $frame++) { $trj->CurrentFrame = $frame; # get the normal vector of the plane my $normal = $plane->BestFitPlane->UnitNormalVector; foreach my $setMolecule(@$setMolecules) { # z position of the molecule my $distance = $setMolecule->Center->Z; # get dipole moment my $dipoleMoment = $setMolecule->DipoleMoment; my $direction=Normalize($dipoleMoment); # calculate the angle between the dipole and the surface normal my $cosAngle = InProduct($direction,$normal); my $angle =180/pi*acos($cosAngle); # store the data in the study table $std->Cell($irow,0) = $angle; $std->Cell($irow++,1) = $distance; } } $doc->Discard; # discard any changes made sub InProduct{ my($a, $b) = @_; return $a->X*$b->X+$a->Y*$b->Y+$a->Z*$b->Z }

Thank you very much! Have a good day!

Winston

  • Comment on The problem of getting the unit vector "Undefined subroutine &main::Normalize"
  • Download Code

Replies are listed 'Best First'.
Re: The problem of getting the unit vector "Undefined subroutine &main::Normalize"
by GrandFather (Saint) on Aug 30, 2017 at 01:16 UTC

    A couple of minor coding related comments:

    for (my $frame = 201; $frame <= 300; $frame++)

    is better written:

    for my $frame (201 .. 300)

    Perl treats $a and $b as somewhat special variables (see sort) so it's usually best to avoid them unless the sort context version of the variables is what you really mean.

    Premature optimization is the root of all job security

      Thanks! I will try that.

Re: The problem of getting the unit vector "Undefined subroutine &main::Normalize"
by NetWallah (Canon) on Aug 30, 2017 at 00:44 UTC
    Who supplies the implementation of the "sub Normalize{...}" ?

    If it comes from the package "MaterialsScript", you can access it via:

    my $direction=MaterialsScript::Normalize($dipoleMoment);
    (You may have to massage the parameters if it is an OO call)

    (It appears that "Normalize" may not be exported by "MaterialsScript", even though you requested ":all".)

                    All power corrupts, but we need electricity.

      Thanks! It seems that I need to write the sub Normalize by myself. I thought Normalize is a function in perl....

        "Normalize" means different things in different contexts.

        The one you seek could very well have already been written and available inside a free CPAN module .. You need to set the context, and search.

        If you have trouble finding a pre-written one on CPAN, post back here with an explanation of what you expect "Normalize" to do, and what kind of parameters you are passing in .. Monks are eager to help.

        It appears you are dealing with Molecular Chemistry - if so perlmol may be of interest.

                        All power corrupts, but we need electricity.