# QMol_DFT_density - fmauger1/QMol-grid GitHub Wiki

`QMol_DFT_density`

One-body-density object

# Description

Use `QMol_DFT_density`

to store the one-body density for (TD)DFT simulations. `QMol_DFT_density`

is a handle class.

# Class properties

## One-body density

The `QMol_DFT_density`

class defines the following public get-access properties; each can be changed using the `set`

method:

`density (rho)`

Discretization of the one-body density `[ vector (default []) ]`

- For spin restricted DFT model; irrelevant for spin restricted ones
- Properly allocated
`density`

is a`numel(`

`disc`

`.xspan)-by-1`

vector matching the domain discretization of the associated (TD)DFT model

`densityUp (rhoUp)`

Discretization of the up-spin channel one-body density `[ vector (default []) ]`

- For spin polarized DFT model; irrelevant for spin restricted ones
- Properly allocated
`densityUp`

is a`numel(`

`disc`

`.xspan)-by-1`

vector matching the domain discretization of the associated (TD)DFT model

`densityDown (rhoDw)`

Discretization of the down-spin channel one-body density `[ vector (default []) ]`

- For spin polarized DFT model; irrelevant for spin restricted ones
- Properly allocated
`densityDown`

is a`numel(`

`disc`

`.xspan)-by-1`

vector matching the domain discretization of the associated (TD)DFT model

`isSpinPol`

Whether the one-body density is spin polarized (`true`

) or spin restricted (`false`

). `isSpinPol`

is used by other classes to determine whether they should use the `density`

or `densityUp`

and `densityDown`

properties in their calculations.

## One-body density gradient

If necessary, the `QMol_DFT_density`

class also provides support for the gradient of the one-body density. Gradient properties can be accessed like the one-body density ones above but cannot be assigned a value with the `set`

property or `clear`

ed; use specific gradient properties instead.

`D_rho`

For spin-restricted models, gradient of the one-body density property.

`D_rhoUp`

For spin-polarized models, gradient of the up-spin one-body density property.

`D_rhoDw`

For spin-polarized models, gradient of the down-spin one-body density property.

## Other properties

These properties cannot be edited with the `set`

method.

`isInitialized (isInit)`

Whether the density object is properly initialized. This is used throughout the QMol-grid package to check that the density object holds meaningful information and is ready for use. Changing its `isSpinPol`

may cause simulations to fail or produce erroneous results.

# Class methods

## Creation

### constructor

Create a one-body density object with empty class properties.

```
obj = QMol_DFT_density;
```

Create a one-body density object with the `name`

properties set to the specified `value`

. Several `name-value`

pairs can be specified consecutively. Suitable `name`

is any of the one-body density properties and is case insensitive.

```
obj = QMol_DFT_density(name1,value1);
obj = QMol_DFT_density(name1,value1,name2,value2,___);
```

Most often, one-body density objects are created through domain-discretization or DFT objects.

```
obj = disc.DFT_allocateDensity;
obj = DFT.getDensity;
```

## Changing class properties

`set`

Update the `name`

properties of a one-body density object to the specified `value`

. Several `name-value`

pairs can be specified consecutively. Suitable `name`

is any of the one-body density properties and is case insensitive.

```
obj.set(name1,value1);
obj.set(name1,value1,name2,value2,___);
```

This is the common name-value pair assignment method used throughout the QMol-grid package. The `set`

method also `reset`

the class. After running, the `set`

property updates the `isInitialized`

flag to a `false`

value.

`reset`

Reset the object by deleting/re-initializing all run-time properties of the class and updating the `isInitialized`

flag to `false`

.

```
obj.reset;
```

This is the common `reset`

method available to all classes throughout the QMol-grid package.

`clear`

Clear all class properties

```
obj.clear;
```

Clear a specific set of the class properties. Suitable `name`

is any of the one-body density properties and is case insensitive.

```
obj.clear(name1,name2,___);
```

This is the common `clear`

method available to all classes throughout the QMol-grid package. The `clear`

method also `reset`

the class. The `clear`

method can be used to delete specific properties before saving an instance of the `QMol_DFT_density`

class.

## Initializing the object

`initialize`

For computations that do not require computation of the density gradient, initialize the one-body density objects and set the `isInitialized`

flag to `true`

.

```
obj.initialize;
```

- To avoid any mismatch in internal properties,
`initialize`

first`reset`

the object before performing the initialization

For computations that may require computation of the density gradient, also specify the associated domain-discretization object

```
obj.initialize(disc);
```

## Run-time documentation

`getMemoryProfile`

Get an estimate of the memory held by a `QMol_DFT_density`

object with either

```
mem = obj.getMemoryProfile;
mem = obj.getMemoryProfile(false);
```

- The object must be properly
`initialize`

d with a domain discretization. - The estimate only includes the discretization of the one-body density on the domain grid and ignores other (small) properties.
- The output
`mem`

is the estimated size in bytes.

Additionally display the detail of the memory footprint with

```
mem = obj.getMemoryProfile(true);
```

## Comparing densities

The class overloads the `==`

and `~=`

operators to facilitate the comparison between density objects

`eq (==)`

Test if two one-body density objects describe the same density

```
obj1 == obj2
```

- For spin-restricted objects, it is defined as
`all(abs(obj1.density-obj2.density) <= eqTol,'all')`

- For spin polarized objects, it is defined as
`all(abs(obj1.densityUp-obj2.densityUp) <= eqTol,'all') && all(abs(obj1.densityDown-obj2.densityDown) <= eqTol,'all')`

`eqTol = 1e-10`

is a tolerance parameter to account for possible roundoff mismatch between two density objects.- Any mismatch in the size of the two objects density components or spin-polarized/restricted returns a
`false`

result. - If both one-body density objects have been initialized with a domain-discretization object. The equality operator also checks that the to density objects have the same domain discretization
`obj1.disc == obj2.disc`

.

`ne (~=)`

Test if two one-body density objects describe different densities

```
obj1 ~= obj2
```

It is equivalent to `~(obj1`

`==`

`obj2)`

.

## Density gradient

To avoid multiple computations of the same one-body density gradient, the `QMol_DFT_density`

class stores the density gradient the first time it is requested and keeps track as to when it should be recomputed. For end users, the `D_rho`

, `D_rhoUp`

, and `D_rhoDw`

gradient-holding properties can be accessed like regular class properties with the guaranty that (i) they match the one-body density currently held in the object, and (ii) the gradient is computed only when it is needed -- *e.g.*, if only the one-body density is required for computations, the gradient is never computed.

`setGradient`

Force the computation and storage of the one-body density gradient with either

```
obj.setGradient;
obj.setGradient(1);
```

This feature is mostly relevant for QMol-grid internal routines and, most of the time, can be ignored by end users.

`resetGradient`

Force the object to consider the gradient properties as not matching its one-body density. A soft gradient reset with either

```
obj.resetGradient;
obj.resetGradient(false);
```

simply changes the internal run-time flags that keeps track as to whether the gradient properties match the one-body density. A hard reset with

```
obj.resetGradient(true);
```

also releases the memory held by the one-body density gradient.

`getGradient`

Uniform interface for accessing the gradient of the on-body density.

```
D_rho = obj.getGradient(1)
```

For spin-restricted density objects, returns the spatial derivative of the one-body density contained in the `density`

property. The input argument `1`

is for consistency with implementation of the density object in higher dimensions and should always be provided -- otherwise it will cause an error. `D_rho = obj.getGradient(1)`

is equivalent to, but less efficient than, directly accessing the `D_rho`

property with `obj.D_rho`

.

```
D_rho = obj.getGradient(1,true)
D_rho = obj.getGradient(1,false)
```

For spin-polarized density objects, returns the spatial derivative of the one-body density contained in the `densityUp`

and `densityDown`

properties, respectively. The input argument `1`

is for consistency with implementation of the density object in higher dimensions and should always be provided -- otherwise it will cause an error. `D_rho = obj.getGradient(1,true)`

and `D_rho = obj.getGradient(1,false)`

are equivalent to, but less efficient than, directly accessing the `D_rhoUp`

and `D_rhoDw`

properties with `obj.D_rhoUp`

and `obj.D_rhoDw`

, respectively.

# Examples

Create a discretization domain

```
disc = QMol_disc('x',-10:.1:15);
disc.initialize;
```

Create a spin-restricted one-body density object on that domain

```
rho = QMol_DFT_density('isSpinPol',false,'density',3/sqrt(2*pi*3)*exp(-(disc.x(:)-3.5).^2/2/3));
rho.initialize(disc);
```

Display the estimated memory footprint for the object

```
rho.getMemoryProfile(true);
```

```
* One-body density
> density 2.0 KB
> gradient 2.0 KB
```

Note that we initialized the one-body density object with providing the discretization object. This will be required to compute the gradient (next). Plot the one-body density and its gradient

```
figure; hold on
plot(disc.x,rho.density,'-','LineWidth',2,'DisplayName','\rho')
plot(disc.x,rho.D_rho,'-','LineWidth',2','DisplayName','\nabla\rho')
xlabel('position (a.u.)'); xlim(disc.x([1 end]));
ylabel('density/gradient')
legend show
```

# Test suite

Run the test suite for the class in normal or summary mode respectively with

```
QMol_test.test('DFT_density');
QMol_test.test('-summary','DFT_density');
```

# For developers

`QMol_DFT_density`

implements a streamlined version of the `clear`

all method, since it might be called frequently in DFT and TDDFT computations. If adding properties to the class, the streamlined `clear`

all must be updated accordingly; likewise QMol-grid package methods may need update.

After initialization, the domain discretization is stored in the transient property `disc`

for later use, *e.g.*, in computing the density gradient(s). Future version of the QMol-grid package might remove the transient nature of `disc`

.

For computation-speed considerations, the gradient of the one-body density is stored in the transient properties `D_rho`

, `D_rhoUp`

, and `D_rhoDw`

. This avoids computing the same derivative multiple times. Internally, the class keeps track as to whether the values in these indeed corresponds to the one-body density in `rho`

, `rhoUp`

, and `rhoDw`

using the `isGrad`

property (`true`

if they match, `false`

otherwise).

Within the QMol-grid package, the different methods that edit the one-body density will update the `isGrad`

flag accordingly; but this is not an automatic feature. If directly editing the content of any of the `D_rho`

, `D_rhoUp`

, and `D_rhoDw`

, one should also perform a derivative soft-reset with `obj.resetGradient(false)`

.

`QMol_DFT_density`

overloads `QMol_suite`

.

## QMol-grid package methods

`QMol_DFT_density`

defines additional methods restricted to the QMol-grid package (classes overloading `QMol_suite`

).

`getCharge`

Compute the charge held a one-body density object

```
N = obj.getCharge;
```

- For spin-restricted models, the output
`N`

is a scalar containing the numerical evaluation of $`\int \rho (x)~dx`

$ - For spin-polarized models, the output N is a two vector containing the numerical evaluations of $
`\int \rho^{\uparrow } (x)~dx`

$ and $`\int \rho^{\downarrow } (x)~dx`

$ , respectively. Get the overall charge with`sum(obj.getCharge)`

- In all cases,
`getCharge`

requires the density object to have been initialized with a domain discretization object.

`getDensity`

Build the one-body density associated with a set of Kohn-Sham orbitals and occupation coefficients

```
obj.getDensity(occ,KSO);
```

- Updates the one-body density properties to match the input Kohn-Sham orbitals and occupation coefficients
- Input KSO is a properly initialized Kohn-Sham orbital (
`QMol_DFT_orbital`

or`QMol_DFT_orbital_basis`

) object - For spin restricted models, input
`N`

is a vector containing the orbitals' occupations coefficients. - For spin polarized models, input
`N = {Nup,Ndown}`

is a cell containing two vectors with the up- and down-spin orbitals' occupation coefficients, respectively - In all cases, the number of elements in the occupation coefficients is assumed to match the number of orbitals in
`KSO`

. - At the end
`getDensity`

initializes the density object with the domain discretization from input orbital (`KSO.disc`

) to ensure consistency between the two objects.

# Notes

The results displayed in this documentation page were generated using version 01.21 of the QMol-grid package.

`QMol_DFT_density`

was introduced in version 01.00- Version 01.10 integrated support for the density spatial derivative (gradient) to it
- Version 01.10 repatriated
`getCharge`

and`getDensity`

from`QMol_disc`

(and overloading classes) `getMemoryProfile`

was introduced in version 01.10