I would first put all parent categories into one array – then run through that array and get all child categories and their respective posts.
So you could basically build a loop ‘around’ your loop – first loop only queries to a depth of 1 (parent cats) and then the second loop looka a lot like yours, but has the “cild_of” argument. So in this second step you get the child cats and their posts for each parent cat.
// First get all parent cats
$parent_cat_args = array(
'depth' => 1,
'orderby' => 'name',
'order' => 'ASC'
);
$parent_cats = get_categories($parent_cat_args);
and then for each parent…
// then get all child cats and their posts
$child_cat_args = array(
'child_of' => $parent_cat_id,
'orderby' => 'name',
'order' => 'ASC'
);
$child_cats = get_categories($child_cat_args);
foreach($child_cats as $category) {
$args = array(
'showposts' => -1,
'category__in' => array($category->term_id),
'ignore_sticky_posts'=>1
);
$posts=get_posts($args);
if ($posts) {
// …
}
}
You’ll find more details about this over at https://developer.wordpress.org/reference/functions/get_categories/