FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

moleculeCloud.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 2008-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*----------------------------------------------------------------------------*/
00025 
00026 #include "moleculeCloud.H"
00027 #include <finiteVolume/fvMesh.H>
00028 
00029 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00030 
00031 namespace Foam
00032 {
00033     defineParticleTypeNameAndDebug(molecule, 0);
00034     defineTemplateTypeNameAndDebug(Cloud<molecule>, 0);
00035 };
00036 
00037 Foam::scalar Foam::moleculeCloud::kb = 1.380650277e-23;
00038 
00039 Foam::scalar Foam::moleculeCloud::elementaryCharge = 1.602176487e-19;
00040 
00041 Foam::scalar Foam::moleculeCloud::vacuumPermittivity = 8.854187817e-12;
00042 
00043 
00044 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00045 
00046 void Foam::moleculeCloud::buildConstProps()
00047 {
00048     Info<< nl << "Reading moleculeProperties dictionary." << endl;
00049 
00050     const List<word>& idList(pot_.idList());
00051 
00052     constPropList_.setSize(idList.size());
00053 
00054     const List<word>& siteIdList(pot_.siteIdList());
00055 
00056     IOdictionary moleculePropertiesDict
00057     (
00058         IOobject
00059         (
00060             "moleculeProperties",
00061             mesh_.time().constant(),
00062             mesh_,
00063             IOobject::MUST_READ,
00064             IOobject::NO_WRITE,
00065             false
00066         )
00067     );
00068 
00069     forAll(idList, i)
00070     {
00071         const word& id(idList[i]);
00072 
00073         const dictionary& molDict(moleculePropertiesDict.subDict(id));
00074 
00075         List<word> siteIdNames = molDict.lookup("siteIds");
00076 
00077         List<label> siteIds(siteIdNames.size());
00078 
00079         forAll(siteIdNames, sI)
00080         {
00081             const word& siteId = siteIdNames[sI];
00082 
00083             siteIds[sI] = findIndex(siteIdList, siteId);
00084 
00085             if (siteIds[sI] == -1)
00086             {
00087                 FatalErrorIn("moleculeCloud.C") << nl
00088                     << siteId << " site not found."
00089                     << nl << abort(FatalError);
00090             }
00091         }
00092 
00093         molecule::constantProperties& constProp = constPropList_[i];
00094 
00095         constProp = molecule::constantProperties(molDict);
00096 
00097         constProp.siteIds() = siteIds;
00098     }
00099 }
00100 
00101 
00102 void Foam::moleculeCloud::setSiteSizesAndPositions()
00103 {
00104     iterator mol(this->begin());
00105 
00106     for (mol = this->begin(); mol != this->end(); ++mol)
00107     {
00108         const molecule::constantProperties& cP = constProps(mol().id());
00109 
00110         mol().setSiteSizes(cP.nSites());
00111 
00112         mol().setSitePositions(cP);
00113     }
00114 }
00115 
00116 
00117 void Foam::moleculeCloud::buildCellOccupancy()
00118 {
00119     forAll(cellOccupancy_, cO)
00120     {
00121         cellOccupancy_[cO].clear();
00122     }
00123 
00124     iterator mol(this->begin());
00125 
00126     for
00127     (
00128         mol = this->begin();
00129         mol != this->end();
00130         ++mol
00131     )
00132     {
00133         cellOccupancy_[mol().cell()].append(&mol());
00134     }
00135 
00136     forAll(cellOccupancy_, cO)
00137     {
00138         cellOccupancy_[cO].shrink();
00139     }
00140 
00141     il_.ril().referMolecules(cellOccupancy());
00142 }
00143 
00144 
00145 void Foam::moleculeCloud::calculatePairForce()
00146 {
00147     iterator mol(this->begin());
00148 
00149     {
00150         // Real-Real interactions
00151 
00152         molecule* molI = &mol();
00153 
00154         molecule* molJ = &mol();
00155 
00156         const directInteractionList& dil(il_.dil());
00157 
00158         forAll(dil, d)
00159         {
00160             forAll(cellOccupancy_[d],cellIMols)
00161             {
00162                 molI = cellOccupancy_[d][cellIMols];
00163 
00164                 forAll(dil[d], interactingCells)
00165                 {
00166                     List< molecule* > cellJ =
00167                     cellOccupancy_[dil[d][interactingCells]];
00168 
00169                     forAll(cellJ, cellJMols)
00170                     {
00171                         molJ = cellJ[cellJMols];
00172 
00173                         evaluatePair(molI, molJ);
00174                     }
00175                 }
00176 
00177                 forAll(cellOccupancy_[d],cellIOtherMols)
00178                 {
00179                     molJ = cellOccupancy_[d][cellIOtherMols];
00180 
00181                     if (molJ > molI)
00182                     {
00183                         evaluatePair(molI, molJ);
00184                     }
00185                 }
00186             }
00187         }
00188     }
00189 
00190     {
00191         // Real-Referred interactions
00192 
00193         molecule* molK = &mol();
00194 
00195         referredCellList& ril(il_.ril());
00196 
00197         forAll(ril, r)
00198         {
00199             const List<label>& realCells = ril[r].realCellsForInteraction();
00200 
00201             forAll(ril[r], refMols)
00202             {
00203                 referredMolecule* molL(&(ril[r][refMols]));
00204 
00205                 forAll(realCells, rC)
00206                 {
00207                     List<molecule*> cellK = cellOccupancy_[realCells[rC]];
00208 
00209                     forAll(cellK, cellKMols)
00210                     {
00211                         molK = cellK[cellKMols];
00212 
00213                         evaluatePair(molK, molL);
00214                     }
00215                 }
00216             }
00217         }
00218     }
00219 }
00220 
00221 
00222 void Foam::moleculeCloud::calculateTetherForce()
00223 {
00224     const tetherPotentialList& tetherPot(pot_.tetherPotentials());
00225 
00226     iterator mol(this->begin());
00227 
00228     for (mol = this->begin(); mol != this->end(); ++mol)
00229     {
00230         if (mol().tethered())
00231         {
00232             vector rIT = mol().position() - mol().specialPosition();
00233 
00234             label idI = mol().id();
00235 
00236             scalar massI = constProps(idI).mass();
00237 
00238             vector fIT = tetherPot.force(idI, rIT);
00239 
00240             mol().a() += fIT/massI;
00241 
00242             mol().potentialEnergy() += tetherPot.energy(idI, rIT);
00243 
00244             // What to do here?
00245             // mol().rf() += rIT*fIT;
00246         }
00247     }
00248 }
00249 
00250 
00251 void Foam::moleculeCloud::calculateExternalForce()
00252 {
00253     iterator mol(this->begin());
00254 
00255     for (mol = this->begin(); mol != this->end(); ++mol)
00256     {
00257         mol().a() += pot_.gravity();
00258     }
00259 }
00260 
00261 
00262 void Foam::moleculeCloud::removeHighEnergyOverlaps()
00263 {
00264     Info<< nl << "Removing high energy overlaps, limit = "
00265         << pot_.potentialEnergyLimit()
00266         << nl << "Removal order:";
00267 
00268     forAll(pot_.removalOrder(), rO)
00269     {
00270         Info<< ' ' << pot_.idList()[pot_.removalOrder()[rO]];
00271     }
00272 
00273     Info<< nl ;
00274 
00275     label initialSize = this->size();
00276 
00277     buildCellOccupancy();
00278 
00279     // Real-Real interaction
00280     iterator mol(this->begin());
00281 
00282     {
00283         mol = this->begin();
00284 
00285         molecule* molI = &mol();
00286 
00287         molecule* molJ = &mol();
00288 
00289         DynamicList<molecule*> molsToDelete;
00290 
00291         const directInteractionList& dil(il_.dil());
00292 
00293         forAll(dil, d)
00294         {
00295             forAll(cellOccupancy_[d],cellIMols)
00296             {
00297                 molI = cellOccupancy_[d][cellIMols];
00298 
00299                 forAll(dil[d], interactingCells)
00300                 {
00301                     List< molecule* > cellJ =
00302                     cellOccupancy_[dil[d][interactingCells]];
00303 
00304                     forAll(cellJ, cellJMols)
00305                     {
00306                         molJ = cellJ[cellJMols];
00307 
00308                         if (evaluatePotentialLimit(molI, molJ))
00309                         {
00310                             label idI = molI->id();
00311 
00312                             label idJ = molJ->id();
00313 
00314                             if
00315                             (
00316                                 idI == idJ
00317                              || findIndex(pot_.removalOrder(), idJ)
00318                                 < findIndex(pot_.removalOrder(), idI)
00319                             )
00320                             {
00321                                 if (findIndex(molsToDelete, molJ) == -1)
00322                                 {
00323                                     molsToDelete.append(molJ);
00324                                 }
00325                             }
00326                             else if (findIndex(molsToDelete, molI) == -1)
00327                             {
00328                                 molsToDelete.append(molI);
00329                             }
00330                         }
00331                     }
00332                 }
00333             }
00334 
00335             forAll(cellOccupancy_[d],cellIOtherMols)
00336             {
00337                 molJ = cellOccupancy_[d][cellIOtherMols];
00338 
00339                 if (molJ > molI)
00340                 {
00341                     if (evaluatePotentialLimit(molI, molJ))
00342                     {
00343                         label idI = molI->id();
00344 
00345                         label idJ = molJ->id();
00346 
00347                         if
00348                         (
00349                             idI == idJ
00350                          || findIndex(pot_.removalOrder(), idJ)
00351                             < findIndex(pot_.removalOrder(), idI)
00352                         )
00353                         {
00354                             if (findIndex(molsToDelete, molJ) == -1)
00355                             {
00356                                 molsToDelete.append(molJ);
00357                             }
00358                         }
00359                         else if (findIndex(molsToDelete, molI) == -1)
00360                         {
00361                             molsToDelete.append(molI);
00362                         }
00363                     }
00364                 }
00365             }
00366         }
00367 
00368         forAll (molsToDelete, mTD)
00369         {
00370             deleteParticle(*(molsToDelete[mTD]));
00371         }
00372     }
00373 
00374     buildCellOccupancy();
00375 
00376     // Real-Referred interaction
00377 
00378     {
00379         molecule* molK = &mol();
00380 
00381         DynamicList<molecule*> molsToDelete;
00382 
00383         referredCellList& ril(il_.ril());
00384 
00385         forAll(ril, r)
00386         {
00387             referredCell& refCell = ril[r];
00388 
00389             forAll(refCell, refMols)
00390             {
00391                 referredMolecule* molL = &(refCell[refMols]);
00392 
00393                 List <label> realCells = refCell.realCellsForInteraction();
00394 
00395                 forAll(realCells, rC)
00396                 {
00397                     label cellK = realCells[rC];
00398 
00399                     List<molecule*> cellKMols = cellOccupancy_[cellK];
00400 
00401                     forAll(cellKMols, cKM)
00402                     {
00403                         molK = cellKMols[cKM];
00404 
00405                         if (evaluatePotentialLimit(molK, molL))
00406                         {
00407                             label idK = molK->id();
00408 
00409                             label idL = molL->id();
00410 
00411                             if
00412                             (
00413                                 findIndex(pot_.removalOrder(), idK)
00414                                     < findIndex(pot_.removalOrder(), idL)
00415                             )
00416                             {
00417                                 if (findIndex(molsToDelete, molK) == -1)
00418                                 {
00419                                     molsToDelete.append(molK);
00420                                 }
00421                             }
00422 
00423                             else if
00424                             (
00425                                 findIndex(pot_.removalOrder(), idK)
00426                                     == findIndex(pot_.removalOrder(), idL)
00427                             )
00428                             {
00429                                 if
00430                                 (
00431                                     Pstream::myProcNo() == refCell.sourceProc()
00432                                  && cellK <= refCell.sourceCell()
00433                                 )
00434                                 {
00435                                     if (findIndex(molsToDelete, molK) == -1)
00436                                     {
00437                                         molsToDelete.append(molK);
00438                                     }
00439                                 }
00440 
00441                                 else if
00442                                 (
00443                                     Pstream::myProcNo() < refCell.sourceProc()
00444                                 )
00445                                 {
00446                                     if (findIndex(molsToDelete, molK) == -1)
00447                                     {
00448                                         molsToDelete.append(molK);
00449                                     }
00450                                 }
00451                             }
00452                         }
00453                     }
00454                 }
00455             }
00456         }
00457 
00458         forAll (molsToDelete, mTD)
00459         {
00460             deleteParticle(*(molsToDelete[mTD]));
00461         }
00462     }
00463 
00464     buildCellOccupancy();
00465 
00466     label molsRemoved = initialSize - this->size();
00467 
00468     if (Pstream::parRun())
00469     {
00470         reduce(molsRemoved, sumOp<label>());
00471     }
00472 
00473     Info<< tab << molsRemoved << " molecules removed" << endl;
00474 }
00475 
00476 
00477 void Foam::moleculeCloud::initialiseMolecules
00478 (
00479     const IOdictionary& mdInitialiseDict
00480 )
00481 {
00482     Info<< nl
00483         << "Initialising molecules in each zone specified in mdInitialiseDict."
00484         << endl;
00485 
00486     const cellZoneMesh& cellZones = mesh_.cellZones();
00487 
00488     if (!cellZones.size())
00489     {
00490         FatalErrorIn("void Foam::moleculeCloud::initialiseMolecules")
00491             << "No cellZones found in the mesh."
00492             << abort(FatalError);
00493     }
00494 
00495     forAll (cellZones, z)
00496     {
00497         const cellZone& zone(cellZones[z]);
00498 
00499         if (zone.size())
00500         {
00501             if (!mdInitialiseDict.found(zone.name()))
00502             {
00503                 Info<< "No specification subDictionary for zone "
00504                     << zone.name() << " found, skipping." << endl;
00505             }
00506             else
00507             {
00508                 const dictionary& zoneDict =
00509                     mdInitialiseDict.subDict(zone.name());
00510 
00511                 const scalar temperature
00512                 (
00513                     readScalar(zoneDict.lookup("temperature"))
00514                 );
00515 
00516                 const vector bulkVelocity(zoneDict.lookup("bulkVelocity"));
00517 
00518                 List<word> latticeIds
00519                 (
00520                     zoneDict.lookup("latticeIds")
00521                 );
00522 
00523                 List<vector> latticePositions
00524                 (
00525                     zoneDict.lookup("latticePositions")
00526                 );
00527 
00528                 if(latticeIds.size() != latticePositions.size())
00529                 {
00530                     FatalErrorIn("Foam::moleculeCloud::initialiseMolecules")
00531                         << "latticeIds and latticePositions must be the same "
00532                         << " size." << nl
00533                         << abort(FatalError);
00534                 }
00535 
00536                 diagTensor latticeCellShape
00537                 (
00538                     zoneDict.lookup("latticeCellShape")
00539                 );
00540 
00541                 scalar latticeCellScale = 0.0;
00542 
00543                 if (zoneDict.found("numberDensity"))
00544                 {
00545                     scalar numberDensity = readScalar
00546                     (
00547                         zoneDict.lookup("numberDensity")
00548                     );
00549 
00550                     if (numberDensity < VSMALL)
00551                     {
00552                         WarningIn("moleculeCloud::initialiseMolecules")
00553                             << "numberDensity too small, not filling zone "
00554                             << zone.name() << endl;
00555 
00556                         continue;
00557                     }
00558 
00559                     latticeCellScale = pow
00560                     (
00561                         latticeIds.size()/(det(latticeCellShape)*numberDensity),
00562                         (1.0/3.0)
00563                     );
00564                 }
00565                 else if (zoneDict.found("massDensity"))
00566                 {
00567                     scalar unitCellMass = 0.0;
00568 
00569                     forAll(latticeIds, i)
00570                     {
00571                         label id = findIndex(pot_.idList(), latticeIds[i]);
00572 
00573                         const molecule::constantProperties& cP(constProps(id));
00574 
00575                         unitCellMass += cP.mass();
00576                     }
00577 
00578                     scalar massDensity = readScalar
00579                     (
00580                         zoneDict.lookup("massDensity")
00581                     );
00582 
00583                     if (massDensity < VSMALL)
00584                     {
00585                         WarningIn("moleculeCloud::initialiseMolecules")
00586                             << "massDensity too small, not filling zone "
00587                             << zone.name() << endl;
00588 
00589                         continue;
00590                     }
00591 
00592 
00593                     latticeCellScale = pow
00594                     (
00595                         unitCellMass/(det(latticeCellShape)*massDensity),
00596                         (1.0/3.0)
00597                     );
00598                 }
00599                 else
00600                 {
00601                     FatalErrorIn("Foam::moleculeCloud::initialiseMolecules")
00602                         << "massDensity or numberDensity not specified " << nl
00603                         << abort(FatalError);
00604                 }
00605 
00606                 latticeCellShape *= latticeCellScale;
00607 
00608                 vector anchor(zoneDict.lookup("anchor"));
00609 
00610                 bool tethered = false;
00611 
00612                 if (zoneDict.found("tetherSiteIds"))
00613                 {
00614                     tethered = bool
00615                     (
00616                         List<word>(zoneDict.lookup("tetherSiteIds")).size()
00617                     );
00618                 }
00619 
00620                 const vector orientationAngles
00621                 (
00622                     zoneDict.lookup("orientationAngles")
00623                 );
00624 
00625                 scalar phi
00626                 (
00627                     orientationAngles.x()*mathematicalConstant::pi/180.0
00628                 );
00629 
00630                 scalar theta
00631                 (
00632                     orientationAngles.y()*mathematicalConstant::pi/180.0
00633                 );
00634 
00635                 scalar psi
00636                 (
00637                     orientationAngles.z()*mathematicalConstant::pi/180.0
00638                 );
00639 
00640                 const tensor R
00641                 (
00642                     cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
00643                     cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
00644                     sin(psi)*sin(theta),
00645                     - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
00646                     - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
00647                     cos(psi)*sin(theta),
00648                     sin(theta)*sin(phi),
00649                     - sin(theta)*cos(phi),
00650                     cos(theta)
00651                 );
00652 
00653                 // Find the optimal anchor position.  Finding the approximate
00654                 // mid-point of the zone of cells and snapping to the nearest
00655                 // lattice location.
00656 
00657                 vector zoneMin = VGREAT*vector::one;
00658 
00659                 vector zoneMax = -VGREAT*vector::one;
00660 
00661                 forAll (zone, cell)
00662                 {
00663                     const point cellCentre = mesh_.cellCentres()[zone[cell]];
00664 
00665                     if (cellCentre.x() > zoneMax.x())
00666                     {
00667                         zoneMax.x() = cellCentre.x();
00668                     }
00669                     if (cellCentre.x() < zoneMin.x())
00670                     {
00671                         zoneMin.x() = cellCentre.x();
00672                     }
00673                     if (cellCentre.y() > zoneMax.y())
00674                     {
00675                         zoneMax.y() = cellCentre.y();
00676                     }
00677                     if (cellCentre.y() < zoneMin.y())
00678                     {
00679                         zoneMin.y() = cellCentre.y();
00680                     }
00681                     if (cellCentre.z() > zoneMax.z())
00682                     {
00683                         zoneMax.z() = cellCentre.z();
00684                     }
00685                     if (cellCentre.z() < zoneMin.z())
00686                     {
00687                         zoneMin.z() = cellCentre.z();
00688                     }
00689                 }
00690 
00691                 point zoneMid = 0.5*(zoneMin + zoneMax);
00692 
00693                 point latticeMid = inv(latticeCellShape) & (R.T()
00694                 & (zoneMid - anchor));
00695 
00696                 point latticeAnchor
00697                 (
00698                     label(latticeMid.x() + 0.5*sign(latticeMid.x())),
00699                     label(latticeMid.y() + 0.5*sign(latticeMid.y())),
00700                     label(latticeMid.z() + 0.5*sign(latticeMid.z()))
00701                 );
00702 
00703                 anchor += (R & (latticeCellShape & latticeAnchor));
00704 
00705                 // Continue trying to place molecules as long as at
00706                 // least one molecule is placed in each iteration.
00707                 // The "|| totalZoneMols == 0" condition means that the
00708                 // algorithm will continue if the origin is outside the
00709                 // zone.
00710 
00711                 label n = 0;
00712 
00713                 label totalZoneMols = 0;
00714 
00715                 label molsPlacedThisIteration = 0;
00716 
00717                 while
00718                 (
00719                     molsPlacedThisIteration != 0
00720                  || totalZoneMols == 0
00721                 )
00722                 {
00723                     label sizeBeforeIteration = this->size();
00724 
00725                     bool partOfLayerInBounds = false;
00726 
00727                     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00728                     // start of placement of molecules
00729                     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00730 
00731                     if (n == 0)
00732                     {
00733                         // Special treatment is required for the first position,
00734                         // i.e. iteration zero.
00735 
00736                         labelVector unitCellLatticePosition(0,0,0);
00737 
00738                         forAll(latticePositions, p)
00739                         {
00740                             label id = findIndex(pot_.idList(), latticeIds[p]);
00741 
00742                             const vector& latticePosition =
00743                             vector
00744                             (
00745                                 unitCellLatticePosition.x(),
00746                                 unitCellLatticePosition.y(),
00747                                 unitCellLatticePosition.z()
00748                             )
00749                             + latticePositions[p];
00750 
00751                             point globalPosition =
00752                             anchor + (R & (latticeCellShape & latticePosition));
00753 
00754                             partOfLayerInBounds =
00755                             mesh_.bounds().contains(globalPosition);
00756 
00757                             label cell = mesh_.findCell(globalPosition);
00758 
00759                             if (findIndex(zone, cell) != -1)
00760                             {
00761                                 createMolecule
00762                                 (
00763                                     globalPosition,
00764                                     cell,
00765                                     id,
00766                                     tethered,
00767                                     temperature,
00768                                     bulkVelocity
00769                                 );
00770                             }
00771                         }
00772                     }
00773                     else
00774                     {
00775                         // Place top and bottom caps.
00776 
00777                         labelVector unitCellLatticePosition(0,0,0);
00778 
00779                         for
00780                         (
00781                             unitCellLatticePosition.z() = -n;
00782                             unitCellLatticePosition.z() <= n;
00783                             unitCellLatticePosition.z() += 2*n
00784                         )
00785                         {
00786                             for
00787                             (
00788                                 unitCellLatticePosition.y() = -n;
00789                                 unitCellLatticePosition.y() <= n;
00790                                 unitCellLatticePosition.y()++
00791                             )
00792                             {
00793                                 for
00794                                 (
00795                                     unitCellLatticePosition.x() = -n;
00796                                     unitCellLatticePosition.x() <= n;
00797                                     unitCellLatticePosition.x()++
00798                                 )
00799                                 {
00800                                     forAll(latticePositions, p)
00801                                     {
00802                                         label id = findIndex
00803                                         (
00804                                             pot_.idList(),
00805                                             latticeIds[p]
00806                                         );
00807 
00808                                         const vector& latticePosition =
00809                                         vector
00810                                         (
00811                                             unitCellLatticePosition.x(),
00812                                             unitCellLatticePosition.y(),
00813                                             unitCellLatticePosition.z()
00814                                         )
00815                                         + latticePositions[p];
00816 
00817                                         point globalPosition = anchor
00818                                         + (R
00819                                         &(latticeCellShape & latticePosition));
00820 
00821                                         partOfLayerInBounds =
00822                                         mesh_.bounds().contains(globalPosition);
00823 
00824                                         label cell = mesh_.findCell
00825                                         (
00826                                             globalPosition
00827                                         );
00828 
00829                                         if (findIndex(zone, cell) != -1)
00830                                         {
00831                                             createMolecule
00832                                             (
00833                                                 globalPosition,
00834                                                 cell,
00835                                                 id,
00836                                                 tethered,
00837                                                 temperature,
00838                                                 bulkVelocity
00839                                             );
00840                                         }
00841                                     }
00842                                 }
00843                             }
00844                         }
00845 
00846                         for
00847                         (
00848                             unitCellLatticePosition.z() = -(n-1);
00849                             unitCellLatticePosition.z() <= (n-1);
00850                             unitCellLatticePosition.z()++
00851                         )
00852                         {
00853                             for (label iR = 0; iR <= 2*n -1; iR++)
00854                             {
00855                                 unitCellLatticePosition.x() = n;
00856 
00857                                 unitCellLatticePosition.y() = -n + (iR + 1);
00858 
00859                                 for (label iK = 0; iK < 4; iK++)
00860                                 {
00861                                     forAll(latticePositions, p)
00862                                     {
00863                                         label id = findIndex
00864                                         (
00865                                             pot_.idList(),
00866                                             latticeIds[p]
00867                                         );
00868 
00869                                         const vector& latticePosition =
00870                                         vector
00871                                         (
00872                                             unitCellLatticePosition.x(),
00873                                             unitCellLatticePosition.y(),
00874                                             unitCellLatticePosition.z()
00875                                         )
00876                                         + latticePositions[p];
00877 
00878                                         point globalPosition = anchor
00879                                         + (R
00880                                         &(latticeCellShape & latticePosition));
00881 
00882                                         partOfLayerInBounds =
00883                                         mesh_.bounds().contains(globalPosition);
00884 
00885                                         label cell = mesh_.findCell
00886                                         (
00887                                             globalPosition
00888                                         );
00889 
00890                                         if (findIndex(zone, cell) != -1)
00891                                         {
00892                                             createMolecule
00893                                             (
00894                                                 globalPosition,
00895                                                 cell,
00896                                                 id,
00897                                                 tethered,
00898                                                 temperature,
00899                                                 bulkVelocity
00900                                             );
00901                                         }
00902                                     }
00903 
00904                                     unitCellLatticePosition =
00905                                     labelVector
00906                                     (
00907                                         - unitCellLatticePosition.y(),
00908                                         unitCellLatticePosition.x(),
00909                                         unitCellLatticePosition.z()
00910                                     );
00911                                 }
00912                             }
00913                         }
00914                     }
00915 
00916                     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00917                     // end of placement of molecules
00918                     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00919 
00920                     if
00921                     (
00922                         totalZoneMols == 0
00923                      && !partOfLayerInBounds
00924                     )
00925                     {
00926                         WarningIn("Foam::moleculeCloud::initialiseMolecules()")
00927                             << "A whole layer of unit cells was placed "
00928                             << "outside the bounds of the mesh, but no "
00929                             << "molecules have been placed in zone '"
00930                             << zone.name()
00931                             << "'.  This is likely to be because the zone "
00932                             << "has few cells ("
00933                             << zone.size()
00934                             << " in this case) and no lattice position "
00935                             << "fell inside them.  "
00936                             << "Aborting filling this zone."
00937                             << endl;
00938 
00939                         break;
00940                     }
00941 
00942                     molsPlacedThisIteration =
00943                     this->size() - sizeBeforeIteration;
00944 
00945                     totalZoneMols += molsPlacedThisIteration;
00946 
00947                     n++;
00948                 }
00949             }
00950         }
00951     }
00952 }
00953 
00954 
00955 void Foam::moleculeCloud::createMolecule
00956 (
00957     const point& position,
00958     label cell,
00959     label id,
00960     bool tethered,
00961     scalar temperature,
00962     const vector& bulkVelocity
00963 )
00964 {
00965     const Cloud<molecule>& cloud = *this;
00966 
00967     if (cell == -1)
00968     {
00969         cell = mesh_.findCell(position);
00970     }
00971 
00972     if (cell == -1)
00973     {
00974         FatalErrorIn("Foam::moleculeCloud::createMolecule")
00975             << "Position specified does not correspond to a mesh cell." << nl
00976             << abort(FatalError);
00977     }
00978 
00979     point specialPosition(vector::zero);
00980 
00981     label special = 0;
00982 
00983     if (tethered)
00984     {
00985         specialPosition = position;
00986 
00987         special = molecule::SPECIAL_TETHERED;
00988     }
00989 
00990     const molecule::constantProperties& cP(constProps(id));
00991 
00992     vector v = equipartitionLinearVelocity(temperature, cP.mass());
00993 
00994     v += bulkVelocity;
00995 
00996     vector pi = vector::zero;
00997 
00998     tensor Q = I;
00999 
01000     if (!cP.pointMolecule())
01001     {
01002         pi = equipartitionAngularMomentum(temperature, cP);
01003 
01004         scalar phi(rndGen_.scalar01()*mathematicalConstant::twoPi);
01005 
01006         scalar theta(rndGen_.scalar01()*mathematicalConstant::twoPi);
01007 
01008         scalar psi(rndGen_.scalar01()*mathematicalConstant::twoPi);
01009 
01010         Q = tensor
01011         (
01012             cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi),
01013             cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi),
01014             sin(psi)*sin(theta),
01015             - sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi),
01016             - sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi),
01017             cos(psi)*sin(theta),
01018             sin(theta)*sin(phi),
01019             - sin(theta)*cos(phi),
01020             cos(theta)
01021         );
01022     }
01023 
01024     addParticle
01025     (
01026         new molecule
01027         (
01028             cloud,
01029             position,
01030             cell,
01031             Q,
01032             v,
01033             vector::zero,
01034             pi,
01035             vector::zero,
01036             specialPosition,
01037             constProps(id),
01038             special,
01039             id
01040         )
01041     );
01042 }
01043 
01044 
01045 Foam::label Foam::moleculeCloud::nSites() const
01046 {
01047     label n = 0;
01048 
01049     const_iterator mol(this->begin());
01050 
01051     for (mol = this->begin(); mol != this->end(); ++mol)
01052     {
01053         n += constProps(mol().id()).nSites();
01054     }
01055 
01056     return n;
01057 }
01058 
01059 
01060 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
01061 
01062 Foam::moleculeCloud::moleculeCloud
01063 (
01064     const polyMesh& mesh,
01065     const potential& pot,
01066     bool readFields
01067 )
01068 :
01069     Cloud<molecule>(mesh, "moleculeCloud", false),
01070     mesh_(mesh),
01071     pot_(pot),
01072     cellOccupancy_(mesh_.nCells()),
01073     il_(mesh_, pot_.pairPotentials().rCutMaxSqr(), false),
01074     constPropList_(),
01075     rndGen_(clock::getTime())
01076 {
01077     if (readFields)
01078     {
01079         molecule::readFields(*this);
01080     }
01081 
01082     buildConstProps();
01083 
01084     setSiteSizesAndPositions();
01085 
01086     removeHighEnergyOverlaps();
01087 
01088     calculateForce();
01089 }
01090 
01091 
01092 Foam::moleculeCloud::moleculeCloud
01093 (
01094     const polyMesh& mesh,
01095     const potential& pot,
01096     const IOdictionary& mdInitialiseDict,
01097     bool readFields
01098 )
01099     :
01100     Cloud<molecule>(mesh, "moleculeCloud", false),
01101     mesh_(mesh),
01102     pot_(pot),
01103     il_(mesh_),
01104     constPropList_(),
01105     rndGen_(clock::getTime())
01106 {
01107     if (readFields)
01108     {
01109         molecule::readFields(*this);
01110     }
01111 
01112     clear();
01113 
01114     buildConstProps();
01115 
01116     initialiseMolecules(mdInitialiseDict);
01117 }
01118 
01119 
01120 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
01121 
01122 void Foam::moleculeCloud::evolve()
01123 {
01124     molecule::trackData td0(*this, 0);
01125     Cloud<molecule>::move(td0);
01126 
01127     molecule::trackData td1(*this, 1);
01128     Cloud<molecule>::move(td1);
01129 
01130     molecule::trackData td2(*this, 2);
01131     Cloud<molecule>::move(td2);
01132 
01133     calculateForce();
01134 
01135     molecule::trackData td3(*this, 3);
01136     Cloud<molecule>::move(td3);
01137 }
01138 
01139 
01140 void Foam::moleculeCloud::calculateForce()
01141 {
01142     buildCellOccupancy();
01143 
01144     iterator mol(this->begin());
01145 
01146     // Set accumulated quantities to zero
01147     for (mol = this->begin(); mol != this->end(); ++mol)
01148     {
01149         mol().siteForces() = vector::zero;
01150 
01151         mol().potentialEnergy() = 0.0;
01152 
01153         mol().rf() = tensor::zero;
01154     }
01155 
01156     calculatePairForce();
01157 
01158     calculateTetherForce();
01159 
01160     calculateExternalForce();
01161 }
01162 
01163 
01164 void Foam::moleculeCloud::applyConstraintsAndThermostats
01165 (
01166     const scalar targetTemperature,
01167     const scalar measuredTemperature
01168 )
01169 {
01170     scalar temperatureCorrectionFactor =
01171         sqrt(targetTemperature/measuredTemperature);
01172 
01173     Info<< "----------------------------------------" << nl
01174         << "Temperature equilibration" << nl
01175         << "Target temperature = "
01176         << targetTemperature << nl
01177         << "Measured temperature = "
01178         << measuredTemperature << nl
01179         << "Temperature correction factor = "
01180         << temperatureCorrectionFactor << nl
01181         << "----------------------------------------"
01182         << endl;
01183 
01184     iterator mol(this->begin());
01185 
01186     for (mol = this->begin(); mol != this->end(); ++mol)
01187     {
01188         mol().v() *= temperatureCorrectionFactor;
01189 
01190         mol().pi() *= temperatureCorrectionFactor;
01191     }
01192 }
01193 
01194 
01195 void Foam::moleculeCloud::writeXYZ(const fileName& fName) const
01196 {
01197     OFstream str(fName);
01198 
01199     str << nSites() << nl << "moleculeCloud site positions in angstroms" << nl;
01200 
01201     const_iterator mol(this->begin());
01202 
01203     for (mol = this->begin(); mol != this->end(); ++mol)
01204     {
01205         const molecule::constantProperties& cP = constProps(mol().id());
01206 
01207         forAll(mol().sitePositions(), i)
01208         {
01209             const point& sP = mol().sitePositions()[i];
01210 
01211             str << pot_.siteIdList()[cP.siteIds()[i]]
01212                 << ' ' << sP.x()*1e10
01213                 << ' ' << sP.y()*1e10
01214                 << ' ' << sP.z()*1e10
01215                 << nl;
01216         }
01217     }
01218 }
01219 
01220 
01221 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines