Commit 741dc47a authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Merge branch 'master' into updated_MAC

parents d0829e5f 7794c740
.. External potentials in SWIFT
Folkert Nobels, 25th October 2018
Alejandro Benitez-Llambay, October 2019
External Potentials
===================
......@@ -38,9 +39,17 @@ give a short overview of the potentials that are implemented in the code:
This potential has as free parameters the concentration of the DM halo, the
virial mass (:math:`M_{200}`) and the critical density.
7. Sine wave (sine-wave)
8. Point mass ring (point-mass-ring)
9. Disc Patch (disc-patch)
7. NFW poential + Miyamoto-Nagai potential (nfw_mn): This includes and NFW potential (identical to nfw)
plus an axisymmetric Miyamoto-Nagai potential. The Miyamoto-Nagai potential is given by:
:math:`\Phi(R,z) = - \frac{G M_{d}}{\sqrt{R^2 + \left ( R_d + \sqrt{z^2 + Z_d^2} \right )^2}}`,
where :math:`R^2 = x^2 + y^2` is the projected radius and :math:`M_d`, :math:`R_d`, :math:`Z_d` are the
mass, scalelength and scaleheight of the disk (in internal units), respectively.
8. Sine wave (sine-wave)
9. Point mass ring (point-mass-ring)
10. Disc Patch (disc-patch)
How to implement your own potential
......
......@@ -36,7 +36,7 @@ filename = "constantBox.hdf5"
# Cosmology (must be same as param file)
hubble_param = 0.6777 # same as in param file
Omega_bar = 0.0455 # same as in param file
Omega_bar = 0.0482519 # same as in param file
# Read the glass file
......
# Example to test the external NFW + MN external potential implementation.
# The gas disc is initialized so that the particles are in cicular orbit with that of the NFW + MN potential.
# The initial thickness of the gaseous disk is arbitrarius, so that it readjust while runnig the simulation.
# Parameters of the MN disk should be self-explanatory from the parameter file.
tested with the following options:
./configure --with-hydro=gadget2 --with-ext-potential=nfw_mn --disable-hand-vec
###############################################################################
# This file is part of SWIFT.
# Copyright (c) 2019 Alejandro Benitez-Llambay (alejandro.b.llambay@durham.ac.uk)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import numpy as np
from scipy import special
import matplotlib.pyplot as plt
import h5py
G = 4.299e-6
def mcum(r, c):
a = np.log(1+c*r)-c*r/(1.0+c*r)
b = np.log(1+c)-c/(1.0+c)
return a/b
def MN_Vcirc(R, z, Rd=4.0, Md=3e10, Zd=0.4):
return np.sqrt(G*Md*R**2/(R**2+(Rd+np.sqrt(z**2+Zd**2))**2)**(3./2.))
def get_vcirc_expo(R, Mgas=3e10, Rd=4.0):
sigma0 = Mgas/(2.0*np.pi*Rd**2)
sigma = sigma0*np.exp(-R/Rd)
y = R/(2.0*Rd)
I0 = special.i0(y)
K0 = special.k0(y)
I1 = special.i1(y)
K1 = special.k1(y)
return np.sqrt(4.0*np.pi*G*sigma0*Rd*y**2*(I0*K0-I1*K1))
def dP1(x):
return x*np.exp(-x)
def dP2(x):
return 1.0/np.cosh(x)**2
hlittle = 0.704
rhoc = 2.775e2 * hlittle**2
#halo mass and concentration
#-------------------
m200 = 1.5e12 #Msun
c = 10.0
r200 = (m200/(200*rhoc*4./3.*np.pi))**(1./3.)
#-------------------
#Gaseous disk
#-----------------
npart = int(1e5) #This controls the resolution
md = 7e8
rd = 0.02*r200
zd = 0.1*rd
#-----------------
#MN parameters
#-----------------
MN_Md = 3e10 #Msun
MN_Rd = 4.0 #kpc
MN_Zd = 0.4 #kpc
#-----------------
#Outputfile
#------------------------
outputfile = 'MN_ICs.hdf5' #Output file for SWIFT
#------------------------
x = []
y = []
z = []
phi = []
while(len(x) <= npart):
n = int(4.5e5)
rmin = 0
rmax = 8
zmin = -6
zmax = 6
r0 = rmin+(rmax-rmin)*np.random.rand(n)
z0 = zmin+(zmax-zmin)*np.random.rand(n)
ymin = 0
ymax1 = np.max(dP1(r0))
ymax2 = np.max(dP2(z0))
y1 = ymin+(ymax1-ymin)*np.random.rand(n)
y2 = ymin+(ymax2-ymin)*np.random.rand(n)
k, = np.where( (y1 <= dP1(r0)) & (y2 <= dP2(z0) ) )
phi0 = 2*np.pi*np.random.rand(len(k))
phi.extend(phi0)
x.extend(r0[k]*np.cos(phi0))
y.extend(r0[k]*np.sin(phi0))
z.extend(z0[k])
sample = np.random.randint(0,len(x), npart)
x = np.asarray(x)[:npart]
y = np.asarray(y)[:npart]
z = np.asarray(z)[:npart]
phi = np.asarray(phi)[:npart]
r = np.sqrt(x**2+y**2+z**2)
#Set positions
pgas = np.ones([npart,3])
pgas[:,0] = x*rd
pgas[:,1] = y*rd
pgas[:,2] = z*zd
vgas = np.zeros([npart,3])
rhogas = np.zeros(npart)
ugas = np.ones(npart)*0
mgas = np.ones(npart)*md/npart*1e-10
#Set velocities
Rgas = np.sqrt(pgas[:,0]**2+pgas[:,1]**2)
ksort = np.argsort(Rgas)
vcirc_gas = get_vcirc_expo(Rgas, Mgas=md, Rd=rd) #Approximate the velocity of the disk (better than spherical)
vcirc_dm = np.sqrt(G*mcum(Rgas/r200,c)*m200/(Rgas))
vcirc_MN = MN_Vcirc(Rgas, pgas[:,2], Md=MN_Md, Rd=MN_Rd, Zd=MN_Zd)
vcirc_tot = np.sqrt(vcirc_dm**2+vcirc_gas**2+vcirc_MN**2)
vgas[:,0] = vcirc_tot*np.sin(phi)
vgas[:,1] = -vcirc_tot*np.cos(phi)
boxsize = 400.0 #Boxsize for SWIFT
for i in range(3):
pgas[:,i] += 200
with h5py.File(outputfile,'w') as snap:
header = snap.create_group('Header')
particles = snap.create_group('PartType0')
particles.create_dataset('Coordinates',data=pgas,dtype=np.float32)
particles.create_dataset('Velocities',data=vgas,dtype=np.float32)
particles.create_dataset('InternalEnergy',data=ugas,dtype=np.float32)
particles.create_dataset('Densities',data=rhogas,dtype=np.float32)
particles.create_dataset('Masses',data=mgas,dtype=np.float32)
particles.create_dataset('SmoothingLength',data=np.ones(len(mgas)),dtype=np.float32)
particles.create_dataset('ParticleIDs',data=np.arange(len(mgas)),dtype='uint')
header.attrs['NumPart_ThisFile'] = np.array([len(mgas),0,0,0,0,0], dtype='uint')
header.attrs['NumPart_Total'] = np.array([len(mgas),0,0,0,0,0], dtype='uint')
header.attrs['MassTable'] = np.array([0,0,0,0,0,0], dtype='double')
header.attrs['Time'] = 0
header.attrs['Redshift'] = 0
header.attrs['Flag_Entropy_ICs'] = 0
header.attrs['NumFilesPerSnapshot'] = 1
header.attrs['NumPart_Total_HighWord'] = np.array([0,0,0,0,0,0], dtype='int')
header.attrs['BoxSize'] = boxsize
snap.close()
#!/bin/bash
wget http://virgodb.cosma.dur.ac.uk/swift-webstorage/ICs/IsolatedGalaxies/Isolated_NFW_MN.hdf5
# Define the system of units to use internally.
InternalUnitSystem:
UnitMass_in_cgs: 1.9891E43 # 10^10 solar masses
UnitLength_in_cgs: 3.08567758E21 # 1 kpc
UnitVelocity_in_cgs: 1E5 # km/s
UnitCurrent_in_cgs: 1 # Amperes
UnitTemp_in_cgs: 1 # Kelvin
# Parameters for the self-gravity scheme
Gravity:
eta: 0.025 # Constant dimensionless multiplier for time integration.
theta: 0.7 # Opening angle (Multipole acceptance criterion).
max_physical_baryon_softening: 0.100 # Physical softening length (in internal units).
# Parameters governing the time integration (Set dt_min and dt_max to the same value for a fixed time-step run.)
TimeIntegration:
time_begin: 0. # The starting time of the simulation (in internal units).
time_end: 2. # The end time of the simulation (in internal units).
dt_min: 1e-6 # The minimal time-step size of the simulation (in internal units).
dt_max: 1e-2 # The maximal time-step size of the simulation (in internal units).
# Parameters governing the snapshots
Snapshots:
basename: output # Common part of the name of output files
time_first: 0. # (Optional) Time of the first output if non-cosmological time-integration (in internal units)
delta_time: 0.001 # Time difference between consecutive outputs (in internal units)
# Parameters governing the conserved quantities statistics
Statistics:
delta_time: 1e-2 # Time between statistics output
time_first: 0. # (Optional) Time of the first stats output if non-cosmological time-integration (in internal units)
Scheduler:
max_top_level_cells: 16
# Parameters related to the initial conditions
InitialConditions:
file_name: Isolated_NFW_MN.hdf5 # The file to read
periodic: 0 # Are we running with periodic ICs?
# Parameters for the hydrodynamics scheme
SPH:
minimal_temperature: 1000. # Minimum allowed gas temperature
resolution_eta: 1.2348 # Target smoothing length in units of the mean inter-particle separation (1.2348 == 48Ngbs with the cubic spline kernel).
CFL_condition: 0.2 # Courant-Friedrich-Levy condition for time integration.
h_min_ratio: 0.1 # Minimal smoothing in units of softening.
h_max: 100.
#NFWPotential:
NFW_MNPotential:
useabspos: 0 # 0 -> positions based on centre, 1 -> absolute positions
position: [0.,0.,0.] # Location of centre of isothermal potential with respect to centre of the box (if 0) otherwise absolute (if 1) (internal units)
timestep_mult: 0.01 # Dimensionless pre-factor for the time-step condition, basically determines the fraction of the orbital time we use to do the time integration
epsilon: 0.01 # Softening size (internal units)
concentration: 10.0 # concentration of the Halo
M_200: 150.0 # M200 of the galaxy disk
critical_density: 1.37E-8 # Critical density of the Universe in internal units
Mdisk: 3.0 # Disk mass (internal units)
Rdisk: 4.0 # Disk size (internal units)
Zdisk: 0.4704911 # Disk scale-height (internal units)
#!/bin/bash
if [ ! -e Isolated_NFW_MN.hdf5 ]
then
echo "Fetching initial conditions for the isolated galaxy example..."
./getIC.sh
fi
../../swift -g -G -s --threads=16 isolated_galaxy.yml
......@@ -51,6 +51,8 @@ Statistics:
Scheduler:
max_top_level_cells: 8
cell_split_size: 50
cell_extra_gparts: 100 # (Optional) Number of spare gparts per top-level allocated at rebuild time for on-the-fly creation.
cell_extra_sparts: 100 # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation.
# Parameters related to the initial conditions
InitialConditions:
......@@ -96,22 +98,40 @@ EAGLEEntropyFloor:
Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in.
Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin.
Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor
GEARPressureFloor:
jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor.
# Cooling with Grackle 3.0
GrackleCooling:
cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository)
with_UV_background: 1 # Enable or not the UV background
redshift: -1 # Redshift to use (-1 means time based redshift)
with_metal_cooling: 1 # Enable or not the metal cooling
provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates
provide_specific_heating_rates: 0 # (optional) User provide specific heating rates
self_shielding_method: 0 # (optional) Grackle (<= 3) or Gear self shielding method
max_steps: 10000 # (optional) Max number of step when computing the initial composition
convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition
thermal_time_myr: 5
cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository)
with_UV_background: 1 # Enable or not the UV background
redshift: 0 # Redshift to use (-1 means time based redshift)
with_metal_cooling: 1 # Enable or not the metal cooling
provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates
provide_specific_heating_rates: 0 # (optional) User provide specific heating rates
max_steps: 10000 # (optional) Max number of step when computing the initial composition
convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition
thermal_time_myr: 5 # (optional) Time (in Myr) for adiabatic cooling after a feedback event.
self_shielding_method: -1 # (optional) Grackle (1->3 for Grackle's ones, 0 for none and -1 for GEAR)
self_shielding_threshold_atom_per_cm3: 0.007 # Required only with GEAR's self shielding. Density threshold of the self shielding
# GEAR chemistry model (Revaz and Jablonka 2018)
GEARChemistry:
initial_metallicity: 0.01295
initial_metallicity: 1 # Initial metallicity of the gas (mass fraction)
scale_initial_metallicity: 1 # Should we scale the initial metallicity with the solar one?
GEARPressureFloor:
jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor.
# GEAR star formation model (Revaz and Jablonka 2018)
GEARStarFormation:
star_formation_efficiency: 0.01 # star formation efficiency (c_*)
maximal_temperature: 3e4 # Upper limit to the temperature of a star forming particle
n_stars_per_particle: 4
min_mass_frac: 0.5
# GEAR feedback model
GEARFeedback:
supernovae_energy_erg: 0.1e51 # Energy released by a single supernovae.
yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 # Table containing the yields.
discrete_yields: 0 # Should we use discrete yields or the IMF integrated one?
......@@ -1090,10 +1090,11 @@ int main(int argc, char *argv[]) {
/* Initialize the space with these data. */
if (myrank == 0) clocks_gettime(&tic);
space_init(&s, params, &cosmo, dim, parts, gparts, sparts, bparts, Ngas,
Ngpart, Nspart, Nbpart, periodic, replicate, generate_gas_in_ics,
with_hydro, with_self_gravity, with_star_formation,
with_DM_background_particles, talking, dry_run, nr_nodes);
space_init(&s, params, &cosmo, dim, &hydro_properties, parts, gparts,
sparts, bparts, Ngas, Ngpart, Nspart, Nbpart, periodic,
replicate, generate_gas_in_ics, with_hydro, with_self_gravity,
with_star_formation, with_DM_background_particles, talking,
dry_run, nr_nodes);
/* Initialise the line of sight properties. */
if (with_line_of_sight) los_init(s.dim, &los_properties, params);
......
......@@ -516,8 +516,8 @@ int main(int argc, char *argv[]) {
/* Initialize the space with these data. */
if (myrank == 0) clocks_gettime(&tic);
space_init(&s, params, &cosmo, dim, parts, gparts, sparts, bparts, Ngas,
Ngpart, Nspart, Nbpart, periodic, replicate,
space_init(&s, params, &cosmo, dim, /*hydro_props=*/NULL, parts, gparts,
sparts, bparts, Ngas, Ngpart, Nspart, Nbpart, periodic, replicate,
/*generate_gas_in_ics=*/0, /*hydro=*/N_total[0] > 0, /*gravity=*/1,
/*with_star_formation=*/0, with_DM_background_particles, talking,
/*dry_run=*/0, nr_nodes);
......
......@@ -209,7 +209,10 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
stars/GEAR/stars_debug.h stars/GEAR/stars_part.h \
potential/none/potential.h potential/point_mass/potential.h \
potential/isothermal/potential.h potential/disc_patch/potential.h \
potential/sine_wave/potential.h \
potential/sine_wave/potential.h potential/constant/potential.h \
potential/hernquist/potential.h potential/nfw/potential.h \
potential/nfw_mn/potential.h potential/point_mass_softened/potential.h \
potential/point_mass_ring/potential.h \
star_formation/none/star_formation.h star_formation/none/star_formation_struct.h \
star_formation/none/star_formation_io.h star_formation/none/star_formation_iact.h \
star_formation/QLA/star_formation.h star_formation/QLA/star_formation_struct.h \
......@@ -280,8 +283,8 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h
pressure_floor/GEAR/pressure_floor_iact.h pressure_floor/none/pressure_floor_iact.h \
pressure_floor/GEAR/pressure_floor_struct.h pressure_floor/none/pressure_floor_struct.h \
task_order/GEAR/task_order.h task_order/EAGLE/task_order.h task_order/default/task_order.h \
sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \
sink.h sink_io.h
sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \
sink.h sink_io.h
# Sources and special flags for the gravity library
......
......@@ -22,7 +22,7 @@
/* Config parameters. */
#include "../config.h"
/* Select the correct star model */
/* Select the correct BH model */
#if defined(BLACK_HOLES_NONE)
#include "./black_holes/Default/black_holes.h"
#include "./black_holes/Default/black_holes_iact.h"
......
......@@ -24,13 +24,13 @@
/* Local includes */
#include "engine.h"
/* Load the correct star type */
/* Load the correct BH model */
#if defined(BLACK_HOLES_NONE)
#include "./black_holes/Default/black_holes_io.h"
#elif defined(BLACK_HOLES_EAGLE)
#include "./black_holes/EAGLE/black_holes_io.h"
#else
#error "Invalid choice of star model"
#error "Invalid choice of BH model"
#endif
#endif /* SWIFT_BLACK_HOLES_IO_H */
......@@ -35,7 +35,7 @@
#elif defined(BLACK_HOLES_EAGLE)
#include "./black_holes/EAGLE/black_holes_struct.h"
#else
#error "Invalid choice of black holes function."
#error "Invalid choice of black hole model."
#endif
#endif /* SWIFT_BLACK_HOLES_STRUCT_H */
......@@ -234,6 +234,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts) {
#endif
c->grav.parts = gparts;
c->grav.parts_rebuild = gparts;
/* Fill the progeny recursively, depth-first. */
if (c->split) {
......@@ -1155,7 +1156,12 @@ int cell_pack_sf_counts(struct cell *restrict c,
pcells[0].stars.count = c->stars.count;
pcells[0].stars.dx_max_part = c->stars.dx_max_part;
/* Pack this cell's data. */
pcells[0].grav.delta_from_rebuild = c->grav.parts - c->grav.parts_rebuild;
pcells[0].grav.count = c->grav.count;
#ifdef SWIFT_DEBUG_CHECKS
/* Stars */
if (c->stars.parts_rebuild == NULL)
error("Star particles array at rebuild is NULL! c->depth=%d", c->depth);
......@@ -1164,6 +1170,16 @@ int cell_pack_sf_counts(struct cell *restrict c,
if (pcells[0].stars.delta_from_rebuild > 0 && c->depth == 0)
error("Shifting the top-level pointer is not allowed!");
/* Grav */
if (c->grav.parts_rebuild == NULL)
error("Grav. particles array at rebuild is NULL! c->depth=%d", c->depth);
if (pcells[0].grav.delta_from_rebuild < 0)
error("Grav part pointer moved in the wrong direction!");
if (pcells[0].grav.delta_from_rebuild > 0 && c->depth == 0)
error("Shifting the top-level pointer is not allowed!");
#endif
/* Fill in the progeny, depth-first recursion. */
......@@ -1199,6 +1215,8 @@ int cell_unpack_sf_counts(struct cell *restrict c,
#ifdef SWIFT_DEBUG_CHECKS
if (c->stars.parts_rebuild == NULL)
error("Star particles array at rebuild is NULL!");
if (c->grav.parts_rebuild == NULL)
error("Grav particles array at rebuild is NULL!");
#endif
/* Unpack this cell's data. */
......@@ -1206,6 +1224,9 @@ int cell_unpack_sf_counts(struct cell *restrict c,
c->stars.parts = c->stars.parts_rebuild + pcells[0].stars.delta_from_rebuild;
c->stars.dx_max_part = pcells[0].stars.dx_max_part;
c->grav.count = pcells[0].grav.count;
c->grav.parts = c->grav.parts_rebuild + pcells[0].grav.delta_from_rebuild;
/* Fill in the progeny, depth-first recursion. */
int count = 1;
for (int k = 0; k < 8; k++)
......@@ -1968,6 +1989,7 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset,
c->progeny[k]->grav.count = bucket_count[k];
c->progeny[k]->grav.count_total = c->progeny[k]->grav.count;
c->progeny[k]->grav.parts = &c->grav.parts[bucket_offset[k]];
c->progeny[k]->grav.parts_rebuild = c->progeny[k]->grav.parts;
}
}
......@@ -5603,11 +5625,14 @@ struct spart *cell_add_spart(struct engine *e, struct cell *const c) {
lock_lock(&top->stars.star_formation_lock);
/* Are there any extra particles left? */
if (top->stars.count == top->stars.count_total - 1) {
if (top->stars.count == top->stars.count_total) {
message("We ran out of free star particles!");
/* Release the local lock before exiting. */
if (lock_unlock(&top->stars.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
message("We ran out of star particles!");
atomic_inc(&e->forcerebuild);
return NULL;
}
......@@ -5735,11 +5760,14 @@ struct gpart *cell_add_gpart(struct engine *e, struct cell *c) {
lock_lock(&top->grav.star_formation_lock);
/* Are there any extra particles left? */
if (top->grav.count == top->grav.count_total - 1) {
if (top->grav.count == top->grav.count_total) {
message("We ran out of free gravity particles!");
/* Release the local lock before exiting. */
if (lock_unlock(&top->grav.star_formation_lock) != 0)
error("Failed to unlock the top-level cell.");
message("We ran out of gravity particles!");
atomic_inc(&e->forcerebuild);
return NULL;
}
......
......@@ -273,6 +273,17 @@ struct pcell_sf {
float dx_max_part;
} stars;
/*! Grav. variables */
struct {
/* Distance by which the gpart pointer has moved since the last rebuild */
ptrdiff_t delta_from_rebuild;
/* Number of particles in the cell */
int count;
} grav;
};
/**
......@@ -461,6 +472,9 @@ struct cell {
/*! Pointer to the #gpart data. */
struct gpart *parts;
/*! Pointer to the #spart data at rebuild time. */
struct gpart *parts_rebuild;
/*! This cell's multipole. */
struct gravity_tensors *multipole;
......
......@@ -2532,11 +2532,13 @@ void io_write_output_field_parameter(const char* filename, int with_cosmology) {
/**
* @brief Create the subdirectory for snapshots if the user demanded one.
*
* Does nothing if the directory is '.'
*
* @param dirname The name of the directory.
*/
void io_make_snapshot_subdir(const char* dirname) {
if (strnlen(dirname, PARSER_MAX_LINE_SIZE) > 0) {
if (strcmp(dirname, ".") != 0 && strnlen(dirname, PARSER_MAX_LINE_SIZE) > 0) {